AIX进程内存分配与回收策略及应用开发建议_第1页
AIX进程内存分配与回收策略及应用开发建议_第2页
AIX进程内存分配与回收策略及应用开发建议_第3页
AIX进程内存分配与回收策略及应用开发建议_第4页
AIX进程内存分配与回收策略及应用开发建议_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、 AIX 进程内存分配与回收策略及应用开发建议 目录1. AIX 内存分配回收策略1.1 内存分配观察示例递增分配1.2 内存分配观察示例递减分配1.3 针对长运行程序的空闲内存回收1.4 mallopt 示例 11.5 mallopt 示例 21.6 内存回收 disclaim 策略1.7 disclaim/disclaim64 代码示例1.8 内存碎片对内存回收的影响1.9 通用建议2. 内存监控2.1 观察系统中内存占用最高的进程2.2 寻找内存持续增长的进程2.3 如何通过共享内存 ID 对应关联到该共享内存的进程2.4 如何获取 AIX Kernel 的内存使用率2.5 如何判断系统

2、是否存在内存不足3. 应用开发工具3.1 dbx 使用以及 coredump 定位3.2 内存非法使用检查3.3 内存泄漏检查(report_allocations)3.4 内存泄漏检查示例3.5 proctools 介绍3.6 probevue 介绍3.7 如何将 C 文件与汇编文件对应1.AIX 内存分配回收策略一般而言, 系统会直接在进程空间的free列表中维护其free释放的内存, 以供后续新的分配直接使用,这样可以提高分配效率,不需要每次内存分配都经过系统内核。进程退出后,系统会回收该进程占用的全部内存。注:选择不同的分配策略时,对空闲内存空间的管理策略会有所差异。例如默认的管理结构

3、是cartesian树;而采用watson分配算法时,使用的管理结构是红黑树。Cartesian笛卡尔树参考结构:1.1 内存分配观察示例递增分配进程的详细内存分配情况可以使用svmon来观察,参考如下示例。需要注意,为方便svmon观察,示例代码需要在malloc之后调用memset进行初始化;因为操作系统实际上并不会立即对已申请但尚未访问到的内容分配实际存储空间, 而是推迟到第一次访问时才会实际分配-这即是缺页机制的工作原理。如下是一个申请空间递增的应用,分配/释放大小为2MB-4MB-8MB-16MB, 则通过各阶段的svmon可以看到, 内存页面会持续增长, 从2MB一直增加到16MB

4、 (注意 不是2MB+4MB+.+16MB=30MB) 。Malloc分配2MB,未初始化时:Address Range为0512页,即代表5124096=2MB虚拟地址空间。Virtual取值为2,表示该空间尚未实际分配。初始化后:Virtual取值为513,表明虚存空间已经实际分配。释放之前申请的2MB,重新 申请 4MB 并初始化后:10244096=4MB,此前释放的512页虚拟地址空间被重复利用。释放之前申请的4MB,重新 申请8 8 MB 并初始化后:此前释放的1024页虚拟地址空间被重复利用。释放之前申请的8MB,重新 申请 16 MB 并初始化后:1.2 内存分配观察示例递减分

5、配如示例, 如果是一个申请空间递减的应用, 分配/释放大小为16MB-8MB-4MB-2MB, 通过各阶段的svmon(svmon -nrP )可以看到,内存页面始终维持在16MB。Malloc分配16MB,未初始化时:Address Range为04096页,即代表40964096=16MB虚拟地址空间。Inuse/Virtual取值为2,表示该空间尚未实际分配。初始化后:Virtual=4097页, 虚拟内存已经实际分配。释放之前申请的16MB,重新 申请8 8 MB 并初始化后:释放之前申请的8MB,重新 申请4 4 MB 并初始化后:释放之前申请的4MB,重新 申请2 2 MB 并初始

6、化后:可以看到svmon输出结果没有变化;原因是虽然应用调用了free释放了16MB内存,但系统的处理策略是将该内存置于进程自身的空间块树中管理。下一个8MB分配,实际上是直接从进程已有的16MB空闲块中获取的。但对系统而言,进程管理的空闲块树也对应为该进程的内存消耗,所以其内存占用没有变化。测试代码:1.3 针对长运行程序的空闲内存回收由于上面介绍的内存使用方式,一个常见的现象是,对于长运行进程,其占用的私有内存大小等同于最高峰时间的内存大小。这个现象一般而言,对系统正常运行及性能的影响很小。因为如果系统空闲内存足够,这个问题不存在。而如果内存不足,由于进程本身的空闲块列表没有被引用,根据换

7、页算法,在系统缺页(即可用内存不足)时,很容易被换出。但如果应用进程希望对其空间内存块进行更自主的管理,可以使用mallopt接口。例如,对长运行的程序,定期在其闲时(例如每周日凌晨业务量极低时),调用 mallopt(M_DISCLAIM, 0)释放进程私有空间的free列表。这样可以避免在程序本身没有内存泄漏的情况下,因业务高峰期大量的内存申请造成的进程私有free list增长,而使得进程内存占用过大。实现起来也相当简单(参考如下 mallopt 示例)。参考mallopt函数的帮助信息:1.4 mallopt 示例 11.5 mallopt 示例 21.6 内存回收 disclaim

8、策略如果需要设置使得系统在应用调用 free 之后,即回收其内存,可以在程序启动前设置环境变量(这两种方式都可能对程序性能有很大影响):PSALLOC=early或者MALLOCOPTIONS=disclaim由于PSALLOC=early实际上意味着设置MALLOCOPTIONS=disclaim,且提前分配Paging Space;所以其性能开销还要高于MALLOCOPTIONS=disclaim。但这种机制能够避免Paging Space耗尽时,进程被系统kill掉的可能;详情可以通过在如下aix infocenter网站查询PSALLOC获取。注:老的MALLOCTYPE=3.1也有此

9、效果,但该分配策略往往性能一般,且只适用于32位程序,现在的系统一般不使用了。在设置环境变量MALLOCTYPE=watson的情况下,mallopt(M_DISCLAIM,0)无效;mallopt(M_DISCLAIM,0)只对系统默认的分配策略(即cartesian树分配算法)有效。也可以在代码中直接用disclaim调用。注意 disclaim 调用需要在 free /delete 之前;超过 4G 的内存块需要使用 disclaim64 函数。1.7 disclaim/disclaim64 代码示例1.8 内存碎片对内存回收的影响需要注意的是,上面各种释放进程私有空闲内存列表的方法,在

10、应用出现严重内存碎片的情况下,都存在不足。这种情况需要实际应用程序通过合理设计,避免严重内存碎片。例如一些缓存数据库表的数据结构,可能涉及大量记录的增删,且一般不会一次性全部删除,类似这种情况可能最终造成严重内存碎片;从而使得进程私有空间无法有效回收, 只能存在于进程自身的私有free list中。举一个极端的例子,一个进程申请了4000页内存,但释放时,恰好在每个内存页上保留了一个16字节的数据结构(其他空间均释放)。这样进程的私有内存空间实际上无法进行收缩。因为mallopt(M_DISCLAIM, 0)和disclaim等方法都需要以多个页面为单位进行实际回收。但如果应用设计良好,一般可

11、以避免这类问题:例如一些事务性的应用,在事务处理开始时,大量申请内存;在处理结束后, 就将这些内存释放。这种情况下, 出现大量内存碎片的概率较低。1.9 通用建议一般对内存受限程序的建议是:a. 尽量使用malloc而不是callocb. 提高引用局部性,即仅在数据结构马上要被使用前,对其进行初始化。c. 对大的数据结构,如果使用一次后,后续不再使用,建议调用disclaim回收其分配的内存。参考:/infocenter/aix/v6r1/index.jsp性能管理和调整 性能管理 性能规划和实现 有效的程序设计和实现 内存限制程序:要将数据工作集减至最小,请尝试集中常用数据以及避免对虚拟存储

12、器页面不必要的引用。特别是:i. 用 malloc() 或 calloc() 子例程来仅请求实际需要的空间大小。当实际情况只使用数组的一小部分时,切勿请求然后初始化最大的数组。当您得到一个新页面用来初始化数组元素时,您实际上是强制 VMM 从别处窃取一个实内存页面。随后, 当拥有该页面的进程尝试再次访问它时,会造成缺页故障。malloc() 和 calloc() 子例程的差异不仅仅在接口上。ii. 因为 calloc() 子例程将分配的存储器置零, 它与每一个分配的页面相关, 而 malloc() 子例程只与第一个页面相关。如果您用 calloc() 子例程分配一大块区域, 然后最初只使用一小

13、部分,那么您对系统施加了不必要的负载。不仅这些页面必须初始化;而且如果它们的实内存页面被系统回收(因为系统调页), 那么已初始化但从未使用的页面必须写出到调页空间。这种情况浪费 I/O 和调页空间。iii. 大结构(如缓冲区)的链表可以引起类似的问题。如果您的程序执行大量寻找某个特定关键字的链式跟踪,请考虑保持链接指针和关键字与数据分离或使用散列表方法来代替。iv. 引用局部性也意味着时间上的局部性, 而不仅仅是地址空间上。仅在使用之前初始化数据结构(如果使用的话)。在重负载系统中,在初始化和使用之间长时间驻留的数据结构有帧被窃取(因为系统调页)的危险。然后您的程序就会在开始使用数据结构时发生

14、不必要的缺页故障。v. 同样,如果早先使用一个大结构,然后与程序剩余部分无关联,它应该被释放。使用 free()子例程来释放由 malloc() 或 calloc() 子例程分配的空间是不够的。free() 子例程仅仅释放结构占用的地址范围。要释放实内存和调页空间,也可使用 disclaim() 子例程来放弃空间。对disclaim() 的调用应该在调用 free() 之前进行。2. 内存监控2.1 观察系统中内存占用最高的进程后台运行 3 个 nmem64 进程:./nmem64 -m 2048 -s 3000 -z 80 &按进程使用的虚拟内存进行排序,显示占用最高的前三项:显示虚拟内存占

15、用最高的 3 个进程的详细的内存段分布信息,如下:可以看到,消耗最多虚拟内存的段都是 nmem64 进程的数据段。2.2 寻找内存持续增长的进程可以使用 ps vg 记录当前系统中各进程的内存消耗情况,然后通过比较多次 ps vg 的结果来判断是否存在一些进程有持续的内存增长。说明:进程存在持续内存增长并不一定意味着出现了内存泄漏。由于 AIX 内存分配采用了访问时分配的策略, 进程申请大量内存时系统并不会第一时间分配内存, 而是在进程使用过程中实际访问时才进行分配。由于这种分配策略, 进程在启动初期可能存在内存持续增长的可能 (例如数据库缓存需要一定时间才能完全填充) ;但其增长曲线应该是收

16、敛到具体值的。测试脚本如下:2.3 如何通过共享内存 ID 对应关联到该共享内存的进程在 AIX 系统层面,只要给定共享内存 id,就可以获取 attach 该共享内存的进程列表,方法如下:可以根据其共享段 SID,获得相应的关联进程 pid,如下。注意 ipcs 上看 NATTACH=53,即有 53 个进程 attach 到该共享内存,因此 svmon 结果中,进程列表部分对应列出了 53 个进程 pid。根据相应的 pid 可以获取进程的具体信息:2.4 如何获取 AIX Kernel 的内存使用率kernel大部分内存占用采用跟普通进程一样的内存段方式组织, 比如kernel heap

17、(这部分内存消耗包含文件系统的元数据、内核扩展、第三方驱动等等), 网络buffer,磁盘管理LVM buffer占用, 以及一些RAS特性的buffer占用, 例如light-weight memory trace buffers, component tracebuffers等等。这部分都可以通过svmon -Ss 查询出( 注意这条命令阻塞时间较长)。少部分采用非段方式组织的主要是AIX内存管理的元数据如页表之类。可以通过 perfpmr.sh - - x memdetails.sh 获取kernel内存占用的整体情况,内存分布将输出在中。也可以通过如下方法直接观察 AIX Kernel

18、 内存使用情况:1. 观察AIX内存使用的命令(基于kdb,建议仅在测试环境验证)2. 建议从我们目前实验的几个系统看,超过100G的大分区,一般内核的内存占用实际都在 5%以下。如果客户环境中采用了较多第三方驱动或组件,比例可能偏高一些,建议搭建环境验证一下。此外, 如果系统中存在超大的JFS2文件系统, 包含大量的巨型文件 (比如单个文件数十、 数百GB) ,或者有数以十万、百万计的小文件;则可能观察到较高的JFS2 元数据缓存占用,或者inode缓存占用。这部分内存消耗也会计入AIX kernel,可以通过 cat/proc/sys/fs/jfs2/memory_usage观察到:# c

19、at /proc/sy s/fs/jfs2/memory_usagemetadata cache: 38928384inode cache: 307888128total: 346816512另,文件系统的元数据缓存和inode缓存可以通过如下ioo参数控制这两个参数是比例系数,设置为400时,元数据和inode缓存最多能占据系统内存的16%左右。一般而言,如果分区内存不大或者元数据相关操作不多,使用默认值(AIX7.1为200)通常是可行的。但如果分区内存足够大(比如100GB以上),元数据操作较多,则可以考虑将这两个参数设置为100,可以使得元数据和inode缓存最多占用系统内存的比例下调

20、至4%左右。2.5 如何判断系统是否存在内存不足预期的内存需求是 virtual 页面数加上文件页面数(包括 pers 和 clnt) ,如果这两者之和大于实际配置的内存页面数,即可认为存在内存不足,如下示例:AIX 6.1 TL2版本之后,加入了一个新的available列:The available means number of bytes of memory that can be used without paging working storage.available计算大致的公式是:available = free + numperm - min(numperm,minperm)

21、- minfree注:numperm即文件缓存所占内存;minperm为文件系统内存需要保障的比例(minperm%)换算得到的内存需求;minfree是系统内存池需要保持的空闲容量(vmo参数);available 如果不够了,就会开始 paging 了, 这是目前最直接的判断方法。3.4 应用开发工具3.1 dbx 使用以及 coredump 定位Core dump 定位参考:/developerworks/cn/aix/library/0806_chench_core/dbx 使用参考“General Programming Concepts” “调试程序”部分。下载地址:/infoce

22、nter/aix/v6r1/topic/com.ibm.aix.genprogc/doc/genprogc/genprogc_pdf.pdf3.2 内存非法使用检查大部分的 coredump 都与内存非法使用有关。IBM Rational PurifyPlus 是解决这类问题的最佳工具。使用 Purify 插桩编译后再进行功能测试, 如果测试中发现内存非法使用之类 (包括内存泄漏)的问题, Purify 可以提供 GUI 界面直接关联到出现问题的应用源代码, 这样能够很方便的定位内存使用类的问题。此外,Quantify 组件可以用于分析程序的性能问题。这些工具功能都非常完备。AIX 下可免费使

23、用的非法内存使用检查工具是 Malloc Debug Tool,设置好 MALLOCTYPE 和 MALLOCDEBUG 选项后, 启动程序即可打开 malloc 调试功能。如下是常用的一组选项:MALLOCTYPE=debugMALLOCDEBUG=log,postfree_checking,validate_ptrs,catch_overflow,allow_overread,report_allocations,continue,output:/tmp/malloclog.txt如果允许越界读(一般情况下不会造成严重错误) ,可以在 MALLOCDEBUG 中加入allow_overre

24、ad。打开 MALLOCDEBUG 后默认的行为是发现内存使用错误后调用 abort 终止程序,这样可以在第一时间 core dump 并退出,方便定位问题。但如果不希望终止可以使用 continue 参数,这样对于可以恢复的错误,将仅生成 core,进程会继续执行。或:MALLOCDEBUG=report_allocations,log:extended,stack_depth:8,catch_overflow,allow_overread,postfree_checking,validate_ptrs,continue,output:/tmp/malloclog.txt具体可以参考:/in

25、focenter/aix/v7r1/topic/com.ibm.aix.genprogc/doc/genprogc/debug_malloc.htm注意:使用 MALLOCDEBUG 选项之后,为调试之目的,系统的内存使用可能会成倍增加,所以需要事先预留好系统的可用内存。3.3 内存泄漏检查(report_allocations)MALLOCTYPE/MALLOCDEBUG 环境变量选项也可以用于内存泄露检查,如:MALLOCTYPE=debugMALLOCDEBUG=report_allocations,output:/tmp/malloclog.txt更详细的记录:MALLOCTYPE=d

26、ebugMALLOCDEBUG=report_allocations,log:extended,stack_depth:6,output:/tmp/malloclog.txt原理:report_allocations 选项可以用于帮助发现内存泄露问题, report_allocations 选项采用数据库记录所有分配情况:当成功分配内存时,采用数据库记录分配情况;而在该内存被释放时,则从数据库从删除分配记录;当进程退出时,系统将所有未释放内存的详细信息记录到日志中。注意事项:1. 从上面的原理介绍可以看到, 程序必须退出之后才能确切知道那些内存没有对应的释放操作。因此如果是长运行的程序,必须注

27、册一个退出函数,常见的方法是注册一个信号处理函数,在收到 SIGTERM 或 SIGINT 时调用 exit(0) ,参考如下示例 (sig_handle 定义和注册过程代码已用红色标注)。2. 上述 debug 环境变量应该设置为仅仅对目标测试程序生效,不能直接在用户环境中export,否则将造成大量无关程序的分配信息被记录到日志中,对定位问题造成干扰。3. 激活 Malloc log 之后,对于 32 位程序,每次内存分配大约有 50-100 字节的额外开销;对 64 位程序,每次内存分配有 100-200 字节的额外开销。因此,激活调试选项的应用的内存使用量会有一定的增长,在测试时需要预先准备足够的系统内存。4. 示例如下:参考文章:/developerworks/cn/aix/library/aumallocdebug.html3.4 内存泄漏检查示例示例 1(基本输出) :示例 2(扩展输出) :3.5 proctools 介绍AIX 提供了一系列基于/proc 文件系统的 proctools 工具集用于分析应用问题,例如 procstack用于打印进程当前的栈信息;procldd 显示进程加载的共享库信息;procfiles 显示进程打开的文件信息;procwdx 显示进程当前的工作目录;procsig 显示

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论