基本操作系统提供了很多编写应用程序内存使用情况的服务。可利用工具来辅助分配内存、映射内存和文件并概要分析应用程序的内存使用情况。本节作为背景知识,描述了系统的内存管理体系结构和内存管理策略。
系统内存体系结构介绍
系统使用一种通过软件扩展物理硬件能力的内存管理方案。因为地址空间与实内存不是一一对应的,所以地址空间(以及系统将其与实内存相对应的方法)称为虚拟内存。
内核和硬件子系统相互合作以将虚拟地址转换为物理地址,它们组成了内存管理子系统。内存管理策略由内核采用的操作构成,那些操作保证进程能平等地分享主内存。以下几节更详细地描述了内存管理子系统的特征。
32 位系统的物理地址空间
硬件提供了一个连续的虚拟内存地址范围(从 0x0000000000000 到 0xFFFFFFFFFFFFF)来存取数据。总的可寻址空间超过 1000 TB。内存访问指令生成一个 32 位的地址:4 位用来选择段寄存器,而 28 位用来给出在此段内的偏移量。该寻址方案提供了对 16 个段的访问,每个段最大可达 256 MB。每个段寄存器包含一个 24 位的段标识,该标识成为了该 28 位偏移量的前缀,它们一起构成了虚拟内存地址。所得的 52 位虚拟地址指向一个系统范围的大型单一虚拟内存空间。
该进程空间是一个 32 位的地址空间;即程序使用 32 位指针。然而,每个进程或中断处理程序只可寻址其段标识位于段寄存器中的系统范围虚拟内存空间(段)。进程通过快速更改寄存器可访问超过 16 个段。
64 位系统上的 32 位进程拥有和 32 位系统(232 字节)相同的有效地址空间,但可以访问与 64 位进程可访问的相同虚拟地址空间(280 字节)。
64 位系统的物理地址空间
硬件提供了一个连续的虚拟内存地址范围(从 0x00000000000000000000 到 0xFFFFFFFFFFFFFFFFFFFF)来存取数据。总的可寻址空间超过 1 万亿 TB。内存访问指令生成一个 64 位的地址:36 位用来选择段寄存器,而 28 位用来给出在此段内的偏移量。该寻址方案提供了对超过 6400 万个段的访问,每个段最大可达 256 MB。每个段寄存器包含一个 52 位的段标识,该标识成为了该 28 位偏移量的前缀,它们一起构成了虚拟内存地址。所得的 80 位虚拟地址指向一个系统范围的大型单一虚拟内存空间。
该进程空间是一个 64 位的地址空间;即程序使用 64 位指针。然而,每个进程或中断处理程序只可寻址其段标识位于段寄存器中的系统范围虚拟内存空间(段)。
段寄存器寻址
系统内核以常规方式为所有进程装入某些段寄存器,从而隐式提供了大多数进程所需的内存可寻址性。这些寄存器包括两个内核段、一个共享库段和一个 I/O 设备段,这些段由所有进程共享且其内容对非内核程序是只读的。对于进程的 exec 系统调用还有一个段,在只读的基础上它与其他执行相同程序的进程、包含可读写的库数据的专用共享库数据段,以及进程的专用可读写段一起实现共享。可以使用内存映射技术装入其余的段寄存器以提供更多的内存,或根据内核强加的访问许可权通过内存访问文件。请参阅了解内存映射以获取关于可用的内存映射服务的信息。
通过间接能力提供的系统 32 位寻址和访问给每个进程提供了一个与系统范围虚拟内存空间的实际大小无关的接口。某些段寄存器由所有进程共享,其他段寄存器由进程的子集共享,而另外的一些则只有一个进程才可访问。共享是通过允许两个或更多的进程装入相同的段标识来实现的。
调页空间
为了向有限的实内存空间提供很大的虚拟内存空间,系统使用实内存作为工作空间,并将没有映射的非活动数据和程序保存在磁盘上。包含该数据的磁盘区域称为调页空间。页是一个虚拟内存单位,包含 4 KB 的数据并可在实际存储器和辅助存储器之间传送。当系统需要页面空间中的数据或程序时,它执行以下操作:
查找当前没有活动的内存区域。
确保来自那个内存区域的数据或程序的最新副本位于磁盘的调页空间中。
将新的程序或数据从磁盘上的调页空间读入新释放的内存区域。
内存管理策略
实地址到虚拟地址的地址转换和大多数其他虚拟内存设施由“虚拟内存管理器”(VMM)透明地提供给系统。VMM 实现了虚拟内存,允许创建大于系统的可用物理内存的段。它通过维护一个实内存的空闲页列表(用来检索所需转入内存的页面)来实现这个功能。
VMM 有时必须通过从实内存除去某些当前页数据来补充空闲列表上的页。在需要数据时在内存和磁盘之间移动数据的过程称为“页面调度”。为了完成页面调度,VMM 使用将页分为三类的页面挪用算法,每一类有唯一的进入和退出条件:
工作存储器页
本地文件页
远程文件页
一般来说,工作页拥有最高的优先级,接下来是本地文件页,然后再是远程文件页。
此外,VMM 使用通常所说的时钟算法技术来选择要替换的页。该技术利用每页的访问位作为哪些页最近使用(访问)过的指示。当调用页面挪用程序例程时,它在页帧表中循环,检测每页的访问位。如果没有访问该页且该页是可挪用的(即没有固定并符合其他页面挪用条件),则它被挪用并置于空闲列表上。访问页可能没有被挪用,但其访问位将复位,从而使该访问有效“老化”,这样就可能在下一次发出页面挪用算法时挪用该页。请参阅页面空间程序的需求以获得更多信息。
内存分配
此操作系统的版本 3 对分配给应用程序的存储器使用延迟页面调度时间片技术。这意味着当存储器以子例程(如 malloc)分配给应用程序时,只有在访问该存储器后才会把调页空间分配给该存储器。请参阅使用 malloc 子系统的系统内存分配以获取更多关于系统的分配策略的信息。
了解内存映射
在系统上处理应用程序指令的速度与为获取程序可寻址内存之外的数据所需的访问操作的数量成正比。系统提供了两种方法来减少与这些读写操作相关的处理开销。可将文件数据映射到进程的地址空间中。也可将进程映射到可能由协作进程共享的匿名内存区域中。
通过将文件数据合并入进程地址空间,内存映射文件提供了一种进程存取文件的机制。使用映射文件可显著减少 I/O 数据移动,因为文件数据不必如 read 和 write 子例程所做的那样被复制到进程数据缓冲区中。当超过一个进程映射相同的文件时,其内容将被这些进程共享,这提供了一个低开销的进程同步与通信机制。
已映射的内存内存区域,也称为共享内存区域,可作为在进程间交换数据的大池。可用的子例程不提供进程间的锁定或访问控制。因此,使用共享内存区域的进程必须设置信号控制方法以防止访问冲突,并确保进程不更改其他进程正在使用的数据。在进程间的数据交换量太大以至于无法传送消息,或进程维护一共用的大型数据库时,共享内存区域带来的益处最大。
系统提供了两个映射文件和匿名内存区域的方法。以下子例程都被认为是 shmat 服务,它们特别用于创建并使用来自程序的共享内存段:
shmctl 控制共享内存操作
shmget 获取或创建共享内存段
shmat 连接来自进程的共享内存段。不允许映射块设备。
shmdt 拆离来自进程的共享内存段
disclaim 除去来自共享内存段内指定的地址范围的映射
ftok 子例程提供了 shmget 子例程用来创建共享段的密钥。
第二个服务组都被认为是 mmap 服务,特别用于映射文件,虽然它还可能被用于创建共享内存段。
所有对由文件的 mmap() 产生的内存的有效操作对由块设备的 mmap() 产生的内存的也有效。块设备是一个特殊文件,它提供对给出块接口的设备驱动程序的访问。设备驱动程序的块接口需要大小固定的块中的数据访问。该接口特别用于接口数据。
mmap 服务包括以下子例程:
madvise 将进程的预期调页行为通知系统
mincore 确定内存页的驻留
mmap 将对象文件映射到虚拟内存中。允许一次一个进程地映射块设备。
mprotect 修改内存映射的访问保护
msync 使映射文件与其底层的存储设备同步
munmap 对已映射的内存区域取消映射
msem_init、msem_lock、msem_unlock、msem_remove、msleep 和 mwakeup 子例程提供了对使用 mmap 服务映射的进程的访问控制。
请参阅以下章节以了解更多关于内存映射的信息。
将 mmap 与 shmat 比较
mmap 兼容性注意事项
使用信号子例程
用 shmat 子例程映射文件
用 shmat 子例程映射共享内存
将 mmap 与 shmat 比较
与和使用 shmat 服务一样,可用于使用 mmap 服务映射文件的进程地址空间部分与该进程是 32 位进程还是 64 位进程有关。对于 32 位进程,可用于映射的地址空间部分由 0x30000000-0xCFFFFFFF 范围内的地址组成,总的地址空间高达 2.5 GB。可用于映射文件的地址空间部分由 0x30000000-0xCFFFFFFF 和 0xE0000000-0xEFFFFFFF 范围内的地址组成,总的地址空间高达 2.75 GB。在 AIX 5.2 和更新的版本中,以超大地址空间模型运行的 32 位进程拥有的可用映射范围为 0x30000000-0xFFFFFFFF,总的地址空间高达 3.25 GB。要获得更多关于超大地址空间模型的信息,请参阅理解大地址空间模型。
32 为进程地址空间内的所有可用范围均可用于固定位置和可变位置的映射。在应用程序指定映射所在的地址空间的固定位置时,发生固定位置映射。在应用程序指定由系统确定映射应该所在的位置时,发生可变位置映射。
对于 64 位过程,有两个进程地址空间的地址范围组可用于 mmap 或 shmat 映射。第一个由单个范围 0x07000000_00000000-0x07FFFFFF_FFFFFFFF 组成,可用于固定位置和可变位置映射。第二个地址组仅可用于固定位置映射,由 0x30000000-0xCFFFFFFF、0xE0000000-0xEFFFFFFF 和 0x10_00000000-0x06FFFFFF_FFFFFFFF 范围组成。其最后一个范围(由 0x10_00000000-0x06FFFFFF_FFFFFFFF 组成)也可用于系统装入程序以保留程序文本、数据和堆,这样只有那部分未使用的范围才可用于固定位置映射。
mmap 和 shmat 服务均提供了将多个进程映射到同一对象区域的能力,这样它们就可共享对该对象的寻址能力。然而,通过允许建立相对无限的映射数量,mmap 子例程将其能力延伸到 shmat 子例程所提供的能力之外。在该能力提高每个文件对象或内存段所支持的映射数量的同时,它被证明对某些应用程序无效,这种应用程序中有许多进程将相同的文件数据映射到地址空间中。
mmap 子例程为每个映射到对象的进程提供了一个唯一的对象地址。这是该软件通过为每个进程提供一个唯一的虚拟地址(即通常所说的别名)来完成的。shmat 子例程允许进程共享已映射对象的地址。
因为任何时候对象中的给定页的现存别名里只有一个拥有实地址转换,所以只有一个 mmap 映射可在不导致缺页故障的情况下引用该页。任何通过不同的映射(即不同的别名)对页的引用会导致缺页故障,该故障会造成该页的现存实地址转换无效。结果,必须为其在不同的别名下建立新的转换。进程通过在这些不同的转换中移动它们来共享页。
对于其中许多进程将相同的文件数据映射到其地址空间中的应用程序,该切换进程可能对性能有负面影响。在这些情况下,shmat 子例程可能提供更有效的文件映射能力。
注:
在使用 PowerPC 处理器的系统上,对同一实地址可存在多个虚拟地址。实地址可对不同进程中不同的有效地址拥有别名,而不用切换。因为没有开关,也就没有性能的下降。
在以下情况下,请使用 shmat 服务:
对于 32 位应用程序,同时映射了 11 个或更少的文件,且每个小于 256 MB。
映射大于 256 MB 的文件时。
映射需要在无关(没有父子关系)进程间共享的共享内存区域时。
映射整个文件时。
在以下情况下,请使用 mmap:
要考虑应用程序的可移植性。
同时映射许多文件。
只需要映射文件的一部分。
需要在映射时设置页级别的保护。
需要专用映射。
“扩展的 shmat”能力可用于地址空间有限的 32 位应用程序。如果定义了环境变量 EXTSHM=ON,则在那个环境中执行的进程可以创建并连接多于 11 个的共享内存段。进程可将这些段连接到地址空间中,以获得段的大小。其他段可在相同的 256MB 区域中被连接到第一个段的末尾。进程可在其上连接的地址位于页边界,它是 SHMLBA_EXTSHM 字节的倍数。
对于使用 shmat 功能部件有一些限制。这些共享内存区域不能被作为 I/O 缓冲区(其中缓冲区固定的取消发生在中断处理程序内)使用。使用扩展的 shmat I/O 缓冲区的限制与 mmap 缓冲区的相同。
该环境变量为应用程序执行选项提供了能在 EXTSHM=ON 时连接超过 11 个段的附加功能,或提供在没有设置该环境变量时对 11 个或更少的段的性能更高的访问。此外,“扩展的 shmat”能力只能应用于 32 位进程。
mmap 兼容性注意事项
mmap 服务由不同的标准指定,且通常用作其他操作系统实现中选项的文件映射接口。然而,mmap 子例程的系统实现可能与其他实现不同。mmap 子例程包括以下改进:
不支持映射到进程的专用区域。
映射不被隐式取消。如果映射已经在所指定的范围中存在,指定 MAP_FIXED 的 mmap 操作将失败。
对于专用映射,写入时复制语义在第一次写入引用上创建页的复制。
不支持 I/O 或设备内存的映射。
不支持字符设备或将 mmap 区域用作对字符设备进行读写操作的缓冲区的映射。
madvise 子例程只是为了兼容性而提供的。系统不按照该所指定的建议采取任何操作。
mprotect 子例程允许指定的区域包含未映射的页。在操作中,未映射的页被简单地跳过。
不支持缺省精确映射和 MAP_INHERIT、MAP_HASSEMAPHORE 以及 MAP_UNALIGNED 标志的特定于 OSF/AES 的选项。
使用信号子例程
msem_init、msem_lock、msem_unlock、msem_remove、msleep 和 mwakeup 子例程符合 OSF 应用程序环境规范。它们提供了 IPC 接口(如 semget 和 semop 子例程)的替换物。使用该信号的好处包括高效的串行化方法和由于不必在没有信号争用的情况下建立系统调用而减少了的开销。
信号可在共享内存区域中找到。信号由 msemaphore 结构指定。msemaphore 结构中的所有值应该由 msem_init 子例程调用得出。跟在该调用后可能是 msem_lock 子例程或 msem_unlock 子例程的调用序列,也可能不是。如果 msemaphore 结构值以其他方式产生,信号子例程的结果不确定。
msemaphore 结构的地址为有效数字。应该注意不要修改该结构的地址。如果该结构包含复制自其他地址上的 msemaphore 结构的值,该信号子例程的结果将是不确定的。
在信号结构存在于由 mmap 创建的匿名内存存储器中时,可能会证实信号子例程没有那么高效,特别是在许多进程引用相同的信号时。在这种情况下,应该在由 shmget 和 shmat 子例程创建的共享内存区域以外分配信号结构。
用 shmat 子例程映射文件
映射可用于减少涉及文件内容读写的开销。一旦文件内容被映射到用户内存区域,可像内存中的数据一样使用该数据的指针而不是输入/输出调用操作该文件。磁盘上该文件的副本也可用作该文件的页面调度区域来保存调页空间。
程序可将任何常规文件用作映射数据文件。还可将映射数据文件的功能扩展到包含已编译和可执行对象代码的文件。因为访问映射文件比访问常规文件更快,所以如果其可执行对象文件被映射到文件,系统可更快地装入程序。请参阅用 shmat 子例程创建映射数据文件以获得关于将任何常规文件用作映射数据文件的信息。
要创建作为已映射可执行文件的程序,请使用 cc 或 ld 命令的 -K 标志编译并链接该程序。-K 标志通知链接程序创建页对齐格式的对象文件。就是说,对象文件的每个部件在页界(可被 2 KB 整除的地址)启动。该选项会导致对象文件中某些空的空间,但允许可执行文件被映射到内存。系统将对象文件映射到内存时,对文本和数据部分进行不同的处理。
写入时复制映射文件
要阻止对映射文件的更改立即出现在磁盘上的文件中,请将文件映射为写入时复制文件。该选项创建更改保存在系统页空间中,而不是磁盘上的文件副本上的映射文件。必须选择将这些更改写入磁盘上的副本以保存这些更改。否则在关闭文件时会丢失这些更改。
因为更改不是立即反映在其他用户可能访问的文件的副本中,使用写入时复制映射文件。
系统不检测用 shmat 子例程映射的文件末尾。因此,如果程序通过存储入相应的内存段(映射文件的地方)以在写入时复制映射文件中写入超出文件当前的末尾,则用由零组成的块来扩展磁盘上的实际文件,以此为新的数据好准备。如果程序在关闭文件前没有使用 fsync 子例程,写在文件以前的末尾之外的数据不会被写入磁盘。文件看起来更大了,但只包含所添加的零。因此,在关闭写入时复制映射文件前请始终使用 fsync 子例程。请参阅用 shmat 子例程创建写入时复制的映射数据文件以获取其他信息。
用 shmat 子例程映射共享内存
系统使用与其创建和使用文件相似的方法来使用共享内存段。以更熟悉的文件系统术语来定义用于共享内存的术语对了解共享内存是非常关键的。共享内存术语的定义列表如下:
术语 定义
key 特定的共享段的唯一标识。只要该共享段存在它就与该共享段相关联。在这点上,它与文件的文件名相似。
shmid 为了在特定进程中使用而分配给共享段的标识。它在使用上与文件的文件描述符相似。
attach 指定了进程必须连接一个共享段以使用它。连接共享段与打开文件相似。
detach 指定了一旦进程完成了对共享段的使用,必须将其拆离。拆离共享段与关闭文件相似。
进程间通信(IPC)的局限
此文档描述了 IPC 机制的系统限制。
在某些 UNIX? 系统上,系统管理员可以编辑 /etc/master 文件并定义 IPC 机制(信号、共享内存段和消息队列)的限制。此方法的问题是限制越高,操作系统使用的内存越多,且性能可能受到负面影响。
AIX 使用不同的方法。在 AIX 中定义了 IPC 机制的上限, 它是不可配置的。按需已分配并释放个别 IPC 数据结构,因此内存需求与当前系统的 IPC 机制使用有关。
方法的差别有时会混淆正在安装或使用数据库的用户。最令人费解的限制是每个进程可同时连接的共享内存段的最大数量。对于 64 位进程,共享内存段的最大数量为 268435456。对于 32 位进程,共享内存段的最大数量为 11,除非使用了扩展的 shmat 能力。关于扩展 shmat 的更多信息,请参阅了解内存映射。
下表总结了 IPC 机制的信号量限制。
信号量 4.3.0 4.3.1 4.3.2 5.1 5.2 5.3
32 位内核的信号量标识的最大数量 4096 4096 131072 131072 131072 131072
64 位内核的信号量标识的最大数量 4096 4096 131072 131072 131072 1048576
每个信号量标识的最大信号量 65535 65535 65535 65535 65535 65535
每个 semop 调用的最大操作数量 1024 1024 1024 1024 1024 1024
每个进程的最大撤销条目数量 1024 1024 1024 1024 1024 1024
撤销结构的大小(B) 8208 8208 8208 8208 8208 8208
信号量的最大值 32767 32767 32767 32767 32767 32767
退出时调整的最大值 16384 16384 16384 16384 16384 16384
下表总结了 IPC 机制的消息队列限制。
消息队列 4.3.0 4.3.1 4.3.2 5.1 5.2 5.3
最大消息大小 4 MB 4 MB 4 MB 4 MB 4 MB 4 MB
队列上的最大字节数 4 MB 4 MB 4 MB 4 MB 4 MB 4 MB
32 位内核的消息队列标识的最大数量 4096 4096 131072 131072 131072 131072
64 位内核的消息队列标识的最大数量 4096 4096 131072 131072 131072 1048576
每个队列标识的最大消息数量 524288 524288 524288 524288 524288 524288
下表总结了 IPC 机制的共享内存限制。
共享内存 4.3.0 4.3.1 4.3.2 5.1 5.2 5.3
段的最大大小(32 位进程) 256 MB 2 GB 2 GB 2 GB 2 GB 2 GB
32 位内核的段的最大大小(64 位进程) 256 MB 2 GB 2 GB 64 GB 1 TB 1 TB
64 位内核的段的最大大小(64 位进程) 256 MB 2 GB 2 GB 64 GB 1 TB 32 TB
段的最小大小 1 1 1 1 1 1
共享内存标识的最大数量(32 位内核) 4096 4096 131072 131072 131072 131072
共享内存标识的最大数量(64 位内核) 4096 4096 131072 131072 131072 1048576
每个进程的段的最大数量(32 位进程) 11 11 11 11 11 11
每个进程的段的最大数量(64 位进程) 268435456 268435456 268435456 268435456 268435456 268435456
注:
对于 32 位进程,在使用扩展的 shmat 能力时,每个进程的段的最大数量只受地址空间大小的限制。
AIX 4.3 的 IPC 限制
对于信号和消息队列,该表显示了系统限制
对于共享内存,最大共享内存段大小为 256 GB。
对于没有扩展 shmat 能力的共享内存:
进程可连接最多 11 个共享内存段。
对于有扩展 shmat 能力的共享内存:
当连接共享内存段时,其大小舍入为 4096 字节的倍数
进程可连接的共享内存段数量与可用地址空间相符。最大的可用地址空间大小为 11 个段,或 256 MB 的 11 倍。
如果进程开始执行时环境变量 EXTSHM 的值为 ON,则使用扩展 shmat 能力。
如果使用大或超大地址空间模型,用于连接共享内存段的可用地址空间被减少。关于更多信息,请参阅大程序支持。
AIX 4.3.1 的 IPC 限制
共享内存段的最大大小从 256 MB 上升到 2 GB。当连接大于 256 MB 的共享内存段时,其大小被舍入到 256 MB 的倍数,即使使用了扩展的 shmat 能力。
AIX 4.3.2 的 IPC 限制
消息队列、信号量标识和共享内存段的最大数量为 131072。
每个队列的最大消息数量为 524288。
AIX 5.1 的 IPC 限制
64 位进程的共享内存段的最大大小为 64 GB。32 位进程不能连接大于 2 GB 的共享内存段。
AIX 5.2 的 IPC 限制
64 位进程的共享内存段的最大大小为 1 TB。32 位进程不能连接大于 2 GB 的共享内存段。
使用超大地址空间模型时,无需使用扩展的 shmat,32 位应用程序就可使用 shmat 能力以获取多于 11 个段。要获得更多关于超大地址空间模型的信息,请参阅理解超大地址空间模型。
应用程序可用使用 vmgetinfo 系统调用查询系统的 IPC 限制。
AIX 5.3 的 IPC 限制
对于 64 位进程,共享内存段的最大大小为 32 TB。32 位进程不能连接大于 2 GB 的共享内存段。
使用超大地址空间模型时,无需使用扩展的 shmat,32 位应用程序就可使用 shmat 能力以获取多于 11 个段。要获得更多关于超大地址空间模型的信息,请参阅理解超大地址空间模型。
应用程序可用使用 vmgetinfo 系统调用查询系统的 IPC 限制。
大程序支持
本章提供的信息,主要关于使用大和超大地址空间模型以向程序提供大于由缺省地址空间模型提供的需要的数据区域。大地址空间模型可用于 AIX 4.3 及其更高版本。超大地址空间模型可用于 AIX 5.1 及其更高版本。
注:
本章所讨论的问题仅应用于 32 位进程。有关缺省 32 位地址空间模型和 64 位地址空间模型的信息,请参阅程序地址空间概述和使用 malloc 子系统的系统内存分配。
32 位进程的虚拟地址空间被划分为 16 个 256 兆字节的区域(或段),每个均由独立的硬件寄存器寻址。操作系统将段 2(虚拟地址 0x20000000-0x2FFFFFFF)引用为进程专有段。缺省情况下,此段包含用户堆栈和数据,包括堆。进程专有段也包含进程的 u-block,它由操作系统使用,且不可被应用程序读取。
因为用户数据和堆栈共同使用单一段,所以它们的总计大小要稍小于 256 MB。但是,某些程序需要大数据区域(已初始或未初始的),或它们需要分配大量的内存用于 malloc 或 sbrk 子例程。可以将程序构建为使用大或超大地址空间模型,以允许它们使用最多 2 GB 的数据。
通过提供一个非零的 maxdata 值,可以使现有的程序使用大或超大地址空间模型。maxdata 值既可以从 LDR_CNTRL 环境变量,也可以从可执行文件中的字段获得。一些程序具有缺省地址空间模型的相关性,因此如果使用大地址空间模型运行它们,它们将会中断。
理解大地址空间模型
大地址空间模型允许指定的程序使用多于 256 MB 的数据。其他程序继续使用缺省的地址空间模型。要允许程序使用大地址空间模型,请指定非零的 maxdata 值。通过在构建程序时使用 ld 命令或在执行程序之前导出 LDR_CNTRL 环境变量,您可以指定一个非零的 maxdata 值。
当执行了使用大地址空间模型的程序时,系统保留所需的 256 MB 的段数量以容纳由 maxdata 值指定的数据量。然后,由段 3 开始,将程序的初始数据从可执行文件读取到内存中。在段 3 中开始数据读取,即使 maxdata 值小于 256 MB。使用大地址空间模型,程序可以分别具有最多 8 段或 2 GB 或 3.25 GB 的数据。
在缺省的地址空间模型中,shmat 或 mmap 子例程可以使用 12 段。当使用了大地址空间模型,为数据保留的段数减少了用于 shmat 和 mmap 子例程的段数。因为数据大小最大值为 2 GB,所以至少 2 段一直可用于 shmat 和 mmap 子例程。
当使用了大地址空间模型时,用户堆栈保留在段 2 中。因此,堆栈的大小限制为稍小于 256 MB。但是,程序可以将其用户堆栈重新部署到共享内存段或已分配内存中。
虽然程序中已初始的数据大小可以是大的,但对文本大小仍有限制。在程序的可执行文件中,文本部分的大小加上装入程序部分的大小必须小于 256 MB。这是必需的,如此这些段才会适合单一的只读段(段 1,TEXT 段)。您可以使用 dump 命令检查段大小。
理解超大地址空间模型
超大地址空间模型以与大地址空间模型几乎相同的方法启用大数据程序,但它们之间仍有几点不同。要允许程序使用超大地址空间模型,您必须指定 maxdata 值和动态段分配(dsa)属性。使用 ld 命令或 LDR_CNTRL 环境变量指定 maxdata 值和 DSA 选项。
如果指定了 maxdata 值,则超大地址空间模型遵循大地址空间模型,在该模型中,从段 3 开始程序数据被读取到内存中,且这些数据根据占据了尽可能多的段。但执行期间,剩余的数据段并不被保留为数据区域,而是被动态地获得。直到程序事件区域需要某一段,该段才可由 shmat 或 mmap 子例程使用。使用超大地址空间模型,程序可以具有最多 13 段或 3.25 GB 的数据。在这 13 段中,12 段或 3 GB 可用于 shmat 和 mmap 子例程。
当进程试图将其数据区域扩展到新段时,只要 shmat 或 mmap 子例程未正在使用该段,操作就可以成功执行。程序可以调用 shmdt 或 munmap 子例程,以停止使用段,这样该段可以用于数据区域。然而,段已经被用于数据区域后,它就不再用于其他任何用途,即使数据区域的大小已降低。
如果未和 dsa 属性一起指定 maxdata 值(maxdata = 0),则会使上述行为产生微小的变动。进程将和常规进程一样,在段 2 中保留其数据和堆栈。进程将不具有对全局共享库的访问权,因此进程使用的所有共享库将被专有地装入。按此种方式运行地优点在于,进程具有的 13 个段(3.25 GB)将全部可由 shmat 和 mmap 子例程使用。
为了降低 shmat 或 mmap 子例程使用可能用于数据区域的段的可能性,操作系统使用不同的规则,用于选择要返回的地址(如果未请求指定的地址)。通常,shmat 或 mmap 子例程返回最低的可用段中的地址。当使用了超大地址空间模型时,这些子例程将返回最高的可用段中的地址。只要地址不是位于已经用于数据区域的段中,指定地址的请求就会成功。指定 dsa 属性的所有进程均遵循此行为。
使用超大地址空间模型,可以指定 maxdata 值为零,或指定最大为 0xD0000000 的值。如果指定的 maxdata 值大于 0xAFFFFFFF,则程序将不会使用全局装入的共享库。相反地,所有地共享库将被专有地装入。这可能会影响程序性能。
启用大和超大地址空间模型
如果指定了 maxdata 值,而未指定动态段分配(dsa)属性,则使用大地址空间模型。如果给定了所有的 maxdata 值并指定了 dsa 属性,则使用超大地址空间模型。使用 ld 命令的 -bmaxdata 标志指定 maxdata 值和设置 dsa 属性。
使用以下命令以链接到将为其数据保留最多 8 段的程序:
cc -bmaxdata:0x80000000 sample.o
要链接到 基于 POWER 的平台 上启用的使用超大地址空间模型的程序,请使用以下命令:
cc -bmaxdata:0xD0000000/dsa sample.o
要链接到启用的使用超大地址空间模型的程序,请使用以下命令:
cc -bmaxdata:0xD0000000/dsa sample.o
您可以使现有的程序使用大或超大地址空间模型,方法是使用 LDR_CNTRL 环境变量指定 maxdata 值。例如,使用以下命令运行 a.out 程序(为其数据区域保留 8 段)。
LDR_CNTRL=MAXDATA=0x80000000 a.out
以下命令运行使用超大地址空间模型的 a.out 程序,允许程序的数据大小使用最多 8 段数据:
LDR_CNTRL=MAXDATA=0x80000000@DSA a.out
您也可以修改现有的程序,这样它将使用大或超大地址空间模型。要将现有的 32 位 XCOFF 程序(a.out)的 maxdata 值设置为 0x80000000,请使用以下命令:
/usr/ccs/bin/ldedit -bmaxdata:0x80000000 a.out
如果 maxdata 值为 0x80000000 的 32 位 XCOFF 程序(a.out)还未具有 DSA 属性,则可以使用以下命令添加该属性:
/usr/ccs/bin/ldedit -bmaxdata:0x80000000/dsa a.out
您可以使用 dump 命令检查 maxdata 值,或确定程序是否具有 dsa 属性。
一些程序具有缺省地址空间模型的相关性。如果通过修改程序的可执行文件或设置 LDR_CNTRL 环境变量而指定非零的 maxdata 值,则这些程序终止。
执行使用大数据区域的程序
当您这些使用大地址空间模型的程序时,操作系统尝试修改数据大小软限制以匹配 maxdata 值。如果 maxdata 值大于当前数据大小的硬限制,则在环境变量 XPG_SUS_ENV 的值设置为 ON 时程序不会程序,或者软限制将被设置为当前的硬限制。
如果 maxdata 值小于程序静态数据的大小,则程序不会执行。
在将程序的已初始或未初始数据放置在段 3 及其以后段中之后,计算中断值。中断值定义进程静态数据的结束以及进程的动态可分配数据的开始。使用 malloc、brk 或 sbrk 子例程,进程可以移动中断值以增加数据区域的大小。
例如,如果由程序指定的 maxdata 值为 0x68000000,则最大中断值位于段 9 之间(0x98000000)。brk 子例程将中断值扩展到段边界以外,但数据区域的大小不能超过当前的软数据限制。
setrlimit 子例程允许进程将其软数据限制设置为不超过硬数据限制的任意值。然而,数据区域的最大大小被限制为原来的 maxdata 值,向上舍入为 256 MB 的倍数。
多数的子例程不受大数据程序的影响。shmat 和 mmap 子例程最容易收到影响,这是因为它们具有较少的可以使用的段。如果大数据地址模型程序发生派生,则子进程继承当前的数据资源限制。
特殊注意事项
使用大数据空间的程序需要大量的调页空间。例如,如果使用 2 GB 地址空间的程序试图访问其地址空间中的每个页面,则系统必须具有 2 GB 的调页空间。当调页空间运行低时,操作系统终止进程。使用大数据空间的程序被首先终止,因为它们通常会消耗大量的调页空间。
调试使用大数据模型的程序与调试其他程序相同。dbx 命令可以主动地或从核心转储调试这些大程序。大数据程序的完全核心转储可能相当大。要避免截断的核心文件,请确保 coredump 资源限制足够大,并确保文件系统中具有足够的可用空间以运行您的程序。
某些应用程序可能依赖缺省地址空间模型的特征而进行编写。如果这些程序使用大或超大地址空间模型执行,它们可能不会正常运行。当您运行这些程序时,不要设置 LDR_CNTRL 环境变量。
使用超大地址空间模型的进程必须对它们的程序进行代码更改,以便移动大于 2 GB 程序块中地址空间的中断值。这是采用带符号的值作为参数的 sbrk 系统调用的一个限制。其变通方法是,程序可以多次调用 sbrk 以将中断值移动到需要的位置。
原文链接: |