当前位置: 首页 > news >正文

AArch64内存管理

概述

本指南介绍AArch64中的内存转换,这是内存管理的关键。本文介绍了如何将虚拟地址转换为物理地址、转换表格式以及软件如何管理页表缓存 (TLB)。

这些对于底层代码(例如启动代码或驱动程序)开发人员都很有用。对于编写软件来设置或管理内存管理单元 (MMU) 的人来说尤其重要。

在本指南的最后,您可以检查您学到的知识。了解如何将虚拟地址转换为物理地址,能够命名不同的地址空间,并描述地址空间如何映射到转换阶段。您还将了解软件何时必须执行 TLB 维护,以及 TLB 维护命令的语法。

什么是内存管理

内存管理描述了如何控制对系统内存的访问。每次操作系统或应用程序访问内存时,硬件都会执行内存管理。内存管理是一种向应用程序动态分配内存区域的方法。

为什么需要内存管理

应用处理器旨在运行rich OS(例如Linux),并支持虚拟内存系统。在处理器上执行的软件只能看到虚拟地址,处理器将其转换为物理地址。这些物理地址呈现给内存系统并指向内存中的实际物理位置。

虚拟地址和物理地址

使用虚拟地址的优势在于它允许管理软件(例如操作系统(OS))控制呈现给软件的内存视图。操作系统可以控制哪些内存是可见的,内存中哪些虚拟地址是可见的,以及对内存的访问权限。这允许操作系统对应用程序进行沙箱处理(对一个应用程序隐藏另外一个应用程序的资源),并提供对底层硬件的抽象。 (优点:内存隔离、减少内存碎片化、比物理内存更大的虚拟内存空间

使用虚拟地址的好处之一是操作系统可以将多个碎片化的物理内存区域作为单个连续的虚拟地址空间呈现给应用程序。

虚拟地址也有利于软件开发人员,他们在编写应用程序时不需要知道实际物理内存地址。使用虚拟地址,软件开发人员无需关心物理内存。应用程序只需知道地址转换是由操作系统和硬件共同协作来完成的。

实际上,每个应用程序都可以使用自己的一组虚拟地址,这些地址将映射到物理系统中的不同位置。当操作系统在不同的应用程序之间切换时,它会对映射进行重新配置。这意味着当前应用程序的虚拟地址可以映射到正确的物理位置。

虚拟地址通过映射转换为物理地址。虚拟地址和物理地址之间的映射存储在转换表(有时称为页表)中,如下图所示:

虚拟地址和物理地址

转换表位于内存中并由软件(通常是操作系统或虚拟机管理程序)管理。转换表不是静态的,可以随着软件需求的变化而更新,这会改变虚拟地址和物理地址之间的映射关系。

地址空间

AArch64中有多个独立的虚拟地址空间。下图展示了这些虚拟地址空间:

Armv8-A中的地址空间

上图显示了三个虚拟地址空间:

  • Non-secure EL0和Non-secure EL1
  • Non-secure EL2
  • EL3

每个虚拟地址空间都是独立的,并且有自己的配置和页表。我们通常将这些配置和表格称为“转换机制”。还有Secure EL0、Secure EL1和Secure EL2的虚拟地址空间,但图中没有显示。

由于存在多个虚拟地址空间,因此指明地址位于哪个地址空间非常重要。例如,NS.EL2:0x8000 指的是非安全 EL2 虚拟地址空间中的地址 0x8000。

上图还展示了来自Non-secure EL0和No-secure EL1的虚拟地址会经过两组页表。这些页表支持虚拟化,允许hypervisor虚拟化VM虚拟机看到的物理内存视图。

Armv9‑A 支持上述 Armv8‑A 的所有虚拟地址空间。 Armv9‑A 引入Realm Management Extension (RME)。当实施 RME 时,还存在其他转换机制:

  • Realm EL1和EL0
  • Realm EL2和EL0
  • Realm EL2

在虚拟化中,我们将操作系统控制的转换设置称为第 1 阶段——Stage1。第 1 阶段将虚拟地址转换为中间物理地址 (IPAs)。在第 1 阶段,操作系统认为 IPA 是物理地址空间。然而,虚拟机管理程序控制第2组转换设置,我们称之为第 2 阶段——Stage2。第 2 组转换将 IPAs 转换为物理地址。下图显示了两组转换的工作原理:

阶段2-IPAs到物理地址

尽管页表格式存在不同,Stage1和Stage2的转换过程通常是一样的。

物理地址

除了多个虚拟地址空间之外,AArch64 还具有多个物理地址空间(PAS):

  • Non-secure PAS0
  • Secure PAS
  • Realm PAS(仅限Armv9-A)
  • Root PAS(仅限Armv9-A)

虚拟地址可以映射到哪些物理地址空间取决于处理器当前的安全状态。下面展示了不同安全状态下,虚拟地址可以映射的目标:

  • 非安全状态:虚拟地址只能映射到非安全物理地址
  • 安全状态:虚拟地址可以映射到安全或者非安全物理地址
  • Realm状态:虚拟地址可以映射到Realm或者非安全物理地址
  • Root状态:虚拟地址可以映射到任何物理地址空间

当处于可以看到多个物理地址空间的安全状态时,转换表会控制使用哪个物理地址空间。下图展示了多个物理地址空间的映射关系。

多个物理地址空间的映射

地址大小

AArch64是64位架构,但这并不意味着所有地址都是64位的。

虚拟地址的大小

虚拟地址以 64 位格式存储。因此,加载指令 (LDR) 和存储指令 (STR) 中的地址始终在 X 寄存器中指定。然而,并非 X 寄存器中的所有地址位都是有效的。

下图显示了 AArch64 中虚拟地址空间的布局:

虚拟地址空间大小

EL0/EL1虚拟地址空间有两个区域布局:内核空间和应用空间,如上图左侧所示,内核空间位于顶部,用户空间位于底部(标记为“用户空间”)。内核空间和用户空间具有单独的转换表,意味着它们的映射是独立开的。

对于其他异常等级,只有一个区域位于地址空间底部,如上图右侧所示。

地址空间的每个区域的大小最多为 52 位。然而,每个区域都可以单独减小。TCR_ELx 寄存器中的 TnSZ 字段控制虚拟地址空间的大小。例如,下图展示了 TCR_EL1 控制 EL0/EL1 虚拟地址空间:

虚拟地址空间1

虚拟地址大小表达式为:
v i r t u a l a d d r e s s s i z e i n b y t e s = 2 64 − T C R E L x . T n S Z virtual\ address\ size\ in\ bytes = 2^{64-TCR_ELx.TnSZ} virtual address size in bytes=264TCRELx.TnSZ
虚拟地址也可以表达为地址位数:
N u m b e r o f a d d r e s s b i t s = 64 − T n S Z Number\ of\ address\ bits=64-TnSZ Number of address bits=64TnSZ
因此,如果TCR_EL1.T1SZ设置为32,则EL0/EL1虚拟地址空间大小为2^32字节(0xFFFF_FFFF_0000_00000xFFFF_FFFF_FFFF_FFFF),不在上述地址配置范围的访问均会生成异常即转换错误。这样我们只需要描述打算使用多大的地址空间。例如,假设操作系统内核需要1GB地址空间(30位地址大小),那么只需设置T1SZ为34(64-34=30),就创建了1GB的转换表。

物理地址的大小

物理地址的大小由实现定义,最大为 52 位。 ID_AA64MMFR0_EL1 寄存器报告处理器实现的大小。对于Arm Cortex‑A 处理器,通常为 40 位或 44 位。

中间物理地址的大小

如果转换页表项中指定的输出地址大于实现的最大值,则内存管理单元MMU将生成异常,即地址大小错误。

IPA空间的大小配置方式与虚拟地址空间相同。 VTCR_EL2.T0SZ 控制大小,可以配置的最大大小与处理器支持的物理地址大小相同。这意味着IPA 空间大小不能超过支持的物理地址空间。

地址空间标识——用所属进程标记转换

许多现代操作系统的应用程序似乎都在同一地址区域运行,这就是我们所描述的用户空间。实际上,不同的应用程序需要不同的映射(因为每个应用程序可以看到全部的地址空间,都有自己的独立的页表)。例如,VA 0x8000 的地址转换取决于当前正在运行的应用程序。

理想情况下,我们希望不同应用程序的转换映射操作能够在页表缓存 (TLB) 中共存,以防止 TLB 在上下文切换时失效。但是处理器如何知道要使用哪个版本的 VA 0x8000 转换呢?在 Armv8‑A 中,答案是地址空间标识符(ASIDs)。

对于 EL0/EL1 虚拟地址空间,可以使用页表项属性字段中的 nG 位将转换标记为全局 (G) 或非全局 (nG)。例如,内核映射是全局转换,应用程映射是非全局转换。全局转换适用于当前正在运行的应用程序。非全局转换仅适用于特定应用程序。

非全局转换在 TLB 中用 ASID 进行标记。在查找 一个 TLB 时,将页表项中的 ASID 与当前选择的 ASID 进行比较。如果它们不匹配,则不使用该 TLB 项。下图显示了内核空间中没有 ASID 标记的全局转换和用户空间中带有 ASID 标记的非全局映射:

页表缓存TLB

上图说明多个应用程序的 TLB 项可以在缓存中共存,ASID 决定使用哪个页表项。

虚拟机标识符——使用所属VM标记转换

EL0/EL1 转换还可以使用虚拟机标识符 (VMID) 进行标记。 VMID 允许来自不同 VM 的转换在缓存中共存。这类似于 ASID 用于来自不同应用程序的转换。实际上,这意味着某些转换将同时标记有 VMID 和 ASID,并且两者都必须与要使用的 TLB 条目匹配。

Common not Private

如果系统包含多个处理器,一个处理器上使用的 ASID 和 VMID 在其他处理器上是否具有相同的含义?

对于 Armv8.0‑A 来说,答案是它们不必表示相同的意思。不要求软件在多个处理器上以相同的方式使用给定的 ASID。例如,ASID 5 可能由一个处理器上的计算器使用,并由另一处理器上的 Web 浏览器使用。这意味着由一个处理器创建的 TLB 条目不能被另一处理器使用。

实际上,软件不太可能在不同的处理器上以不同的方式使用 ASID。对于软件来说,更常见的是在给定系统中的所有处理器上以相同的方式使用 ASID 和 VMID。因此,Armv8.2‑A在转换表基址寄存器(TTBR)中引入了Common not Private (CnP)位。当 CnP 位被设置时,软件承诺在所有处理器上以相同的方式使用 ASID 和 VMID,这允许一个处理器创建的 TLB 条目可以由另一个处理器使用。

内存管理单元(MMU)

内存管理单元 (MMU) 负责将软件使用的虚拟地址转换为内存系统中使用的物理地址。

MMU包括如下内容:

  • table walk unit:从内存中读取转换表(查表,完成虚拟地址到物理地址的转换)
  • Translation Lookaside Buffers(TLBs):缓存最近使用的转换(类似cache,将转换映射放入缓存,提高映射效率)

软件分配的所有内存地址都是虚拟的。这些内存地址被传递到 MMU,MMU 检查 TLB 中是否有最近使用的缓存转换。如果 MMU 没有找到最近缓存的转换,table walk unit会从内存中读取相应的表条目,如下所示:

MMU

在访问内存之前,虚拟地址必须转换为物理地址(因为我们必须知道正在访问哪个物理内存)。这种转换需求也适用于缓存数据,因为Armv6及之后处理器,数据缓存了物理地址上存储的数据。因此,在完成缓存查找之前必须转换该虚拟地址。

表项

转换表的工作原理是将虚拟地址空间划分为大小相等的块,并在表中为每个块提供一个条目。

表中的条目 0 提供块 0 的映射,条目 1 提供块 1 的映射,依此类推。每个条目包含相应物理内存块的地址以及访问物理地址时需要使用的属性。

页表项

查表

当进行地址转换时,会进行查表,软件发出的虚拟地址分为两部分,如下图所示。

查表

上图展示了单个页表查找过程。

图中标记为“Which entry”的高位,告诉你需要查看哪个页表项,用于索引转换表。这个页表项存放虚拟地址对应的物理地址的块号。

图中标记为“Offset in block”位,是物理块内的偏移量,直接寻址使用,不会因转换而改变。

多级转换

在单个页表查找中,虚拟地址划分为大小相等的块。但在实际中,经常使用多级页表(因为每个进程都需要一个页表,多级页表主要是用来减少页表占用的内存空间)。

一级页表将虚拟地址划分为比较大的块。该表中的每一项可以指向相同大小的物理内存块,也可以指向另外一个表,其将该内存块划分为更小的块,我们将这种类型的表称为“多级表”。下面我们可以看到一个具有三级页表的示例:

多级转换

在 Armv8‑A 中,最大支持到4级页表,编号为从 0 到 3。这种多级页表允许同时描述较大的块和较小的块,这些块的特点如下:

  • 较大的块比较小的块需要的读取转换更少。另外大块通常缓存在TLBs中,这样比较高效。
  • 小块使软件可以对内存分配进行精细控制。然而,小块在 TLB 中缓存的效率较低,因为小块需要多次读取各个页表才能进行转换。

为了管理这种权衡,操作系统必须在大块映射的效率与小块映射的灵活性之间做出平衡,从而获得最佳性能。

转换表格式

下图我们可以看到转换表允许的不同格式。

转换表格式

每个表项都是64位,最低2两位决定了表项的类型。

请注意,某些表项仅在特定等级下有效。表的最大级别数为四,这就是为什么没有第三级(或第四级)表描述符的原因。类似地,没有0 级块描述符或页描述符。因为 0 级表项覆盖了很大的虚拟地址空间区域,所以标记为块是没有意义的。

转换粒度

转换粒度是可描述的最小内存块。仅可描述比转换粒度大的块,是粒度的倍数。

AArch64 支持三种转换粒度大小:4KB、16KB 和 64KB。

处理器支持的粒度大小是由实现定义的,并由ID_AA64MMFR0_EL1指明。所有 Arm Cortex‑A 处理器都支持 4KB 和 64KB。粒度大小是最新页表等级中可以描述的最小块,更大的块也可以描述。下表是根据不同粒度大小,每一级页表可以描述的块大小。

Level4KB4KB16KB16KB64KB64KB
SizeBitsSizeBitsSizeBits
0512GB47:39128TB47--
14GB38:3064GB46:364TB51:42
22MB29:2132MB35:25512MB41:29
34KB20:1216KB24:1464KB28:16

在推出 Armv9.2‑A 和 Armv8.7‑A 之前,使用 52 位有限制。当选择的粒度为4KB或16KB时,最大虚拟地址区域大小为48位。同样地,输出物理地址也限制为48位。仅当使用64KB粒度大小时,可以使用完整的 52 位大小地址空间。

地址转换起始等级

虚拟地址空间大小和粒度共同控制地址转换的起始等级(即哪个等级开始进行虚拟地址到物理地址的转换操作)。

上表总结了每级页表中每种粒度大小对应的块大小,通过块大小,你可以计算出虚拟地址的哪些位用于索引哪个页表。

以4KB粒度大小为例,下图展示了4KB粒度下哪些位用于索引哪个表。

转换等级

想象一下,你将虚拟地址空间即TCR_ELx.T0SZ设置为32位,则虚拟地址空间的大小计算如下:

64 - T0SZ = 32位地址空间(bits 31:0)

如果我们再次查看前面的 4KB 粒度图,等级 0 由位 47:39 索引。对于 32 位地址空间,您没有这些位。因此,您的配置的起始转换等级为级别 1。

再想象一下,假设你将T0SZ设置为34:

64 - T0SZ = 30位地址空间(bits 29:0)

这次,您没有任何位用于索引 0 级表或 1 级表,因此您的配置的起始转换等级为 2 级。

综上,当虚拟地址空间大小减小时,你需要描述的页表也越少。

这些示例基于使用 4KB 粒度。同样适用于 16KB 和 64KB 粒度,但地址位发生变化。

控制地址转换的寄存器

地址转换由一些系统寄存器控制:

  • SCTLR_ELx
    • M:启用内存管理单元(MMU)
    • C:启用数据缓存和统一缓存
    • EE:转换表遍历的大小端
  • TTBR0_ELx和TTBR1_ELx
    • BADDR:转换表起始的物理地址PA(或者对于EL0/EL1,中间物理地址IPA)
    • ASID:非全局转换的地址空间标识
  • TCR_ELx
    • PS/IPS:PA或IPA空间大小,最大输出地址大小
    • TnSZ:表所覆盖的地址空间大小
    • TGn:粒度大小
    • SH/IRGN/ORGN:MMU遍历使用可缓存性和共享性
    • TBIn:禁用某个表的遍历
  • MRIR_ELx
    • Attr:控制第 1 阶段表的类型和可缓存性

禁用MMU

当 MMU 在转换阶段被禁用时,所有地址都是直接映射的,即意味着输入和输出地址相同。

页表缓存维护

TLBs缓存了最近使用的转换,其允许后续查表复用转换,而无需重新读取表。

如果更改一个转换页表项,或者控制转换,你需要将这个页表项变为无效状态。如果你不这样做,处理器可能还是使用的旧的转换。

处理器不允许缓存会导致错误的转换:

  • 转换错误(未映射的地址)
  • 地址大小错误(地址超出范围)
  • 访问标志错误

因此,首次地址映射时,你不需要发出TLB无效命令。但是,如果您想要执行以下任一操作,则需要发出 TLB 无效命令:

  • 取消地址映射:获取先前有效或映射的地址,并将其标记为错误。
  • 更改地址映射:更改输出地址或者属性。例如,将地址从只读权限更改为读写权限。
  • 更改表转换方式:这种情况不太常见。但是,例如如果粒度大小发生变化,页表转换也需要变化。因此需要发出TLB无效命令。

TLB操作格式

TLBI指令用于将TLB中的表项变为无效。该指令的语法如下:

TLBI < type >< level >{IS|OS} {, < xt >}

其中:

  • < type >:哪些项无效

    • All:所有项
    • VA:与Xt中的VA和ASID相匹配的项
    • VAA:与Xt中的VA匹配的项,适用于任何ASID
    • ASID:与Xt中的ASID匹配的任何项
    • ……
  • < level >:要操作的地址空间

    • E1 = EL0/1虚拟地址空间
    • E2 = EL2虚拟地址空间
    • E3 = EL3虚拟地址空间
  • < IS|OS >:操作是内部共享(IS)还是外部共享(OS)

    • 当 IS 被添加到操作中时,它会广播到内部共享域中的其他core
    • 当 OS 被添加到操作中时,它会广播到外部共享域中的其他core(在 Armv8.4‑A 中添加)。
  • < Xt >:要操作的地址或ASID

    • 仅用于地址或ASID进行的操作

例如,当操作系统考虑更新内核转换表,典型的TLB无效代码如下所示:

STR X1, [X5] 		// Write to translation table entry
DSB ISH 		    // Barrier instructions - not covered in this guide
TLBI VAAE1IS , X0 	 // Invalidate VA specified by X0, in EL0/1// virtual address space for all ASIDs
DSB ISH 		    // Barrier instructions - not covered in this guide
ISB 			   // Synchronize context on this processor

地址转换指令

地址转换(AT)指令允许软件查询某一地址的转换。转换结果(包括属性)将写入物理地址寄存器PAR_EL1中。

AT 指令的语法允许您指定要使用的转换机制。例如,EL2可以查询EL0/EL1转换机制。但是,EL1 不能使用 AT 指令来查询 EL2 转换机制,因为这违反了特权原则。

如果请求的转换会导致错误,但是这不会产生异常。相反,会将生成的故障类型记录在 PAR_EL1 中。

检查你学到的知识

  1. 地址转换中的阶段和等级有什么区别?

    阶段是将输入地址转换为输出地址的过程。对于第 1 阶段,这是从 VA 到 IPA 的过程,对于第 2 阶段,这是从 IPA 到 PA 的过程。

    等级与给定转换阶段的表相关,这也决定如何将较大的块细分为较小的块。

  2. 物理地址的最大大小是多少?

    物理地址空间的最大大小是由实现定义的,最多52位(从Armv8.2-A以后)。

  3. 哪个寄存器字段控制虚拟地址空间的大小?

    TCR_ELx.TnSZ,或者阶段2的VTCR_EL2.T0SZ。

  4. 什么是转换粒度,支持的大小是多少?

    它是可以描述的最小内存块,支持的大小有4KB,16KB,64KB。

  5. 指令TLBI ALLE3 有什么作用?

    它会使 EL3 虚拟地址空间的所有 TLB 条目无效。

  6. 导致转换错误的表项是否可以缓存在 TLB 中?

    不可以,它不能存储在 TLB 中。

  7. 当 MMU 禁用时,地址如何映射?

    地址是恒等映射,即输入和输出地址是相同的。

  8. 什么是 ASID?TLB 条目何时包含 ASID?

    ASID 是地址空间标识符,它标识转换与哪个应用程序(进程)关联。非全局映射 (nG=1) 在 TLB 中用 ASID 进行标记。

相关信息

以下是与本文相关的一些资源:

  • 虚拟化:对于Armv8‑A 和Armv9‑A,此主题在虚拟化中介绍。
  • 有用的培训链接:
    • Introduction to Armv8-A
    • Memory model overview
    • Memory types overview
    • What does architecture consist of?

下一步

本指南介绍了内存管理的概念,解释了虚拟地址到物理地址的映射。了解此信息您将能创建自己的裸机页表,并了解操作系统在分配内存时执行的过程。

Memory Model guide中介绍了内存类型和属性,例如访问权限。

除了处理器中的内存管理单元 (MMU) 之外,用于非处理器主设备的 MMU 也越来越普遍,例如直接内存访问(DMA) 引擎。这些在 Arm 系统中称为 SMMU(系统 MMU),在其他地方称为 IOMMU。

要继续了解 Armv8‑A 架构,请参阅Arm系列文章series of guides。

欢迎关注“安全有理”微信公众号。

安全有理

相关文章:

AArch64内存管理

概述 本指南介绍AArch64中的内存转换&#xff0c;这是内存管理的关键。本文介绍了如何将虚拟地址转换为物理地址、转换表格式以及软件如何管理页表缓存 (TLB)。 这些对于底层代码&#xff08;例如启动代码或驱动程序&#xff09;开发人员都很有用。对于编写软件来设置或管理内…...

导出Excel的技术分享-综合篇

导出Excel的技术分享-综合篇 简单的EasyExcel使用 /*** 最简单的写*/public void simpleWrite() {// 注意 simpleWrite在数据量不大的情况下可以使用&#xff08;5000以内&#xff0c;具体也要看实际情况&#xff09;&#xff0c;数据量大参照 重复多次写入// 写法1 JDK8// s…...

iPhone 14四款机型电池容量详细参数揭秘

苹果推出的iPhone 14系列与2021系列的设计和外形尺寸相同&#xff08;仅缩小了几分之一毫米&#xff09;&#xff0c;所以这并不奇怪&#xff0c;但电池容量也大致相同。 虽然可能不足以对电池寿命产生可衡量的影响&#xff0c;但也存在微小的差异。不同的是&#xff0c;现在有…...

Python功能强大、灵活可扩展的Statsmodels库

Statsmodels是一个功能强大、灵活可扩展的Python库&#xff0c;用于进行统计建模和数据分析。它提供了一系列丰富的统计模型和方法&#xff0c;可以帮助研究人员和数据科学家在Python环境中进行高级统计分析。 概述 在Statsmodels中&#xff0c;线性回归是最常用的统计模型之…...

AcWing 4405. 统计子矩阵(每日一题)

如果你觉得这篇题解对你有用&#xff0c;可以点点关注再走呗~ 题目描述 给定一个 NM 的矩阵 A&#xff0c;请你统计有多少个子矩阵 (最小 11&#xff0c;最大 NM) 满足子矩阵中所有数的和不超过给定的整数 K ? 输入格式 第一行包含三个整数 N,M 和 K。 之后 N 行每行包含 …...

Kali Linux渗透测试技术介绍【文末送书】

文章目录 写在前面一、什么是Kali Linux二、渗透测试基础概述和方法论三、好书推荐1. 书籍简介2. 读者对象3. 随书资源 写作末尾 写在前面 对于企业网络安全建设工作的质量保障&#xff0c;业界普遍遵循PDCA&#xff08;计划&#xff08;Plan&#xff09;、实施&#xff08;Do…...

GPT与BERT模型

NLP任务的核心逻辑是“猜概率”的游戏。BERT和GPT都是基于预训练语言模型的思想&#xff0c;通过大量语料训练得到语言模型。两种模型都是基于Transformer模型。 Bert 类似于Transformer的Encoder部分&#xff0c;GPT类似于Transformer的Decoder部分。两者最明显的在结构上的差…...

2023-09-06力扣每日一题-摆烂暴力

链接&#xff1a; [1123. 最深叶节点的最近公共祖先](https://leetcode.cn/problems/form-smallest-number-from-two-digit-arrays/) 题意&#xff1a; 如题 解&#xff1a; 今天搞一手暴力&#xff0c;按层存&#xff0c;按层取&#xff0c;直到只取到一个 实际代码&…...

【Flutter】Flutter 使用 timego 将日期转换为时间描述

【Flutter】Flutter 使用 timego 将日期转换为时间描述 文章目录 一、前言二、安装与基本使用三、如何添加新的语言四、如何覆盖现有的语言或添加自定义消息五、完整示例六、总结 一、前言 你好&#xff01;我是小雨青年&#xff0c;今天我要为你介绍一个非常实用的 Flutter 包…...

并发容器11

一 JDK 提供的并发容器总结 JDK 提供的这些容器大部分在 java.util.concurrent 包中。 ConcurrentHashMap: 线程安全的 HashMap CopyOnWriteArrayList: 线程安全的 List&#xff0c;在读多写少的场合性能非常好&#xff0c;远远好于 Vector. ConcurrentLinkedQueue: 高效的并…...

Java8实战-总结22

Java8实战-总结22 使用流数值流原始类型流特化数值范围数值流应用&#xff1a;勾股数 使用流 数值流 可以使用reduce方法计算流中元素的总和。例如&#xff0c;可以像下面这样计算菜单的热量&#xff1a; int calories menu.stream().map(Dish::getcalories).reduce(0, Int…...

matlab 实现点云ICP 配准算法

一、算法步骤 (1)在目标点云P中取点集pi∈P; (2)找出源点云Q中的对应点集qi∈Q,使得||qi-pi||=min; (3)计算旋转矩阵R和平移矩阵t,使得误差函数最小; (4)对pi使用上一步求得的旋转矩阵R和平移矩阵t进行旋转和平移变换,的到新的对应点集pi’={pi’=Rpi+t,pi∈P};…...

python提取word文本和word图片

提取文本 docx只支持docx格式&#xff0c;所以如果想读取doc需要另存为docx格式即可 import docx # pip3 install python-docx doc docx.Document(three.docx) for paragraph in doc.paragraphs:print(paragraph.text)提取图片 import zipfile import os, re # docx本质上…...

iOS开发Swift-9-SFSymbols,页面跳转,view屏幕比例,启动页-和风天气AppUI

1.创建项目 2.设置好测试机型,App显示名称,以及关闭横向展示. 3.下载SF Symbols. https://developer.apple.com/sf-symbols/ 右上角搜索 search ,可以找到很多系统自带图标.选择喜欢的图标,拷贝图标的名字. 插入一个Button,在Image中粘贴图标名称并选择,即可将Button变成想要的…...

代码优化工具-测试程序执行时间-IDEAdebug+StopWatch

参考&#xff1a; [技巧]IDEA的debugStopWatch监测程序运行时间 添加链接描述 1创建类StopWatchExpand import lombok.extern.slf4j.Slf4j;import org.springframework.util.StopWatch;import java.text.NumberFormat;/*** 检测程序片段运行时间拓展** author sdevil507* cr…...

力扣每日一题---2594. 修车的最少时间

文章目录 思路解题方法复杂度Code 思路 请注意&#xff0c;能力值越低&#xff0c;修车越快&#xff0c;应该翻译成「排名」&#xff0c;排名越靠前&#xff0c;修车越快。&#xff09;根据题意可以知道r * n * n < t 的&#xff0c;所以可以利用数学知识进行改变公式&#…...

【jvm】运行时数据区

目录 一、运行时数据区一、作用二、说明三、线程共用与私有区域 一、运行时数据区 一、作用 1.内存是非常重要的系统资源&#xff0c;是硬盘和CPU 的中间仓库及桥梁&#xff0c;承载着操作系统和应用程序的实时运行。JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策…...

SpringMVC相对路径和绝对路径

1.相对地址与绝对地址定义 在jsp&#xff0c;html中使用的地址&#xff0c;都是在前端页面中的地址&#xff0c;都是相对地址 地址分类&#xff1a;&#xff08;1&#xff09;&#xff0c;绝对地址&#xff0c;带有协议名称的是绝对地址&#xff0c;http://www.baidu.com&…...

IIS perl python cbrother php脚本语言配置及简单测试样例程序

上篇笔记写了 IIS 配置 CGI&#xff0c; IIS CGI配置和CGI程序FreeBasic, VB6, VC 简单样例_Mongnewer的博客-CSDN博客 这篇在IIS上配置一些脚本语言。为了操作方便&#xff0c;每种语言在站点下分设文件夹。 1. IIS perl配置 Perl CGI方式是曾经流行的做法。先下载一个开源…...

Oracle Scheduler中日期表达式和PLSQL表达式的区别

参考文档&#xff1a; Database Administrator’s Guide 29.4.5.4 Differences Between PL/SQL Expression and Calendaring Syntax Behavior There are important differences in behavior between a calendaring expression and PL/SQL repeat interval. These differenc…...

Java设计模式:一、六大设计原则-06:依赖倒置原则

文章目录 一、定义&#xff1a;依赖倒置原则二、模拟场景&#xff1a;依赖倒置原则三、违背方案&#xff1a;依赖倒置原则3.1 工程结构3.2 抽奖系统**3.2.1 定义抽奖用户类**3.2.2 抽奖控制 3.3 单元测试 四、改善代码&#xff1a;依赖倒置原则4.1 工程结构4.2 抽奖控制改善4.2…...

信息系统数据同步解决方案

实施数据同步解决方案时&#xff0c;重要的是确保数据同步是安全的、可靠的&#xff0c;并且能够适应系统变化。定期测试和监控数据同步过程&#xff0c;以确保其稳定运行&#xff0c;并随着需求的变化进行适当的调整和优化。 应用场景&#xff1a;信息系统A和信息系统B实现员…...

LRU算法 vs Redis近似LRU算法

LRU(Least Recently Use)算法&#xff0c;是用来判断一批数据中&#xff0c;最近最少使用算法。它底层数据结构由Hash和链表结合实现&#xff0c;使用Hash是为了保障查询效率为O(1)&#xff0c;使用链表保障删除元素效率为O(1)。 LRU算法是用来判断最近最少使用到元素&#xf…...

浅析ARMv8体系结构:异常处理机制

文章目录 概述异常类型中断终止Abort复位Reset系统调用 异常处理流程异常入口异常返回异常返回地址 堆栈选择 异常向量表异常向量表的配置 同步异常解析相关参考 概述 异常处理指的是处理器在运行过程中发生了外部事件&#xff0c;导致处理器需要中断当前执行流程转而去处理异…...

Golang开发--Goroutine的使用

Go 语言天生支持并发编程&#xff0c;提供了丰富的原语和工具来编写并发程序。Goroutine 是 Go 语言中的轻量级执行单位。它们是由 Go 运行时&#xff08;runtime&#xff09;管理的&#xff0c;并且能够在单个线程上运行成千上万个 Goroutine。创建 Goroutine 非常高效&#x…...

【Linux】package ‘python-yaml‘ has no installation candidate 如何解决

要解决此问题&#xff0c;可以尝试以下几个步骤&#xff1a; 确保系统已经更新到最新版本。可以使用以下命令进行系统更新&#xff1a; sudo apt update sudo apt upgrade确保您的软件源列表中包含了正确的软件源。可以使用以下命令编辑软件源列表&#xff1a; sudo nano /etc/…...

Selector选择器在AspNetCore中的用法

Selector选择器在AspNetCore中的用法 背景 项目编辑过程中会选择其所属的上级项目&#xff0c;而上级项目在数据结构中是以ParentID的方式表达&#xff0c;而非Project类型&#xff0c;用户不会记录也不应该记录ID值&#xff0c;因此应提供Selector项目下拉框供用户选择。 但…...

anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter

Win11查看安装的Python路径及安装的库 anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter 介绍开源包管理系统和环境管理系统 &#xff0c;包括多种语言的包安装&#xff0c;运行&#xff0c;更新&#xff0c;删除&#xff0c;最重要的是可以解…...

java八股文面试[多线程]——锁的分类

1.1 可重入锁、不可重入锁 Java中提供的synchronized&#xff0c;ReentrantLock&#xff0c;ReentrantReadWriteLock都是可重入锁。 重入&#xff1a;当前线程获取到A锁&#xff0c;在获取之后尝试再次获取A锁是可以直接拿到的。 不可重入&#xff1a;当前线程获取到A锁&…...

儿童安全门和围栏,以及游戏围栏等美国站要求的合规标准是什么?

儿童安全门和围栏 儿童安全门和围栏用于在门口&#xff08;如门道&#xff09;内设置围栏&#xff0c;或用作自支撑围栏&#xff0c;将幼儿可能在其中活动的区域围起来。这些商品可能由塑料、金属、乙烯树脂或木制组件等材料制成。此政策包括但不限于可扩展围栏、伸缩安全门和…...

做旅游网站的关注与回复/seo搜索引擎优化技术教程

...

供应链管理专业研究生/seo技术培训班

如何设立短期目标 知道吗&#xff1f;那些成功人士极力反对的&#xff0c;以及权威人士大力阻止的&#xff0c;而我们又没有发现什么不好的事&#xff0c;或许就是我们苦苦追寻的“成功秘诀”。政府、专家、成功者经常像大人哄孩子一样。难道不是吗&#xff1f;“那是粑粑&…...

法院网站管理系统源码/百度导航下载2022最新版官网

视频微课知识点一、四大发明四大发明是我们国家最伟大的文化成果。包括&#xff1a;造纸术、指南针、火药、活字印刷术。二、人物介绍蔡伦&#xff0c;字敬仲&#xff0c;桂阳郡宋阳(今湖南宋阳)人&#xff0c;生于东汉永平四年(公元61年)&#xff0c;卒于建光元年(公元121年)。…...

网站建设商城/独立站建站需要多少钱

做了这么多年的数据分析和挖掘工作&#xff0c;一直都在思考一个问题&#xff0c;“互联网和金融&#xff0c;在数据挖掘上到底存在什么样的区别”。在对这个问题的摸索和理解过程中&#xff0c;发现数据挖掘本身包含很多层次。模型本身也是存在传统和时髦之分的。本文就想聊聊…...

双公示网站专栏建设/武汉百度推广公司

Java语言提供了很多修饰符&#xff0c;主要分为以下两类&#xff1a;访问修饰符非访问修饰符修饰符用来定义类、方法或者变量&#xff0c;通常放在语句的最前端。我们通过下面的例子来说明&#xff1a; public class className { // ...}private boolean myFlag;static final…...

wordpress4.2.15漏洞/软件开发公司

引言本文引用地址&#xff1a;http://www.eepw.com.cn/article/201238.htm输电线路是电力系统的重要组成部分&#xff0c;其各相相序的准确性关系到电网的安全稳定运行。其工频参数如正序参数、零序参数和互感参数可为电力系统潮流计算和继电保护整定计算提供实际数据&#xff…...