一种Linux内存管理机制
论文作者:草根论文网 论文来源:www.lw360.net 发布时间:2016年12月21日

内存是Linux系统中重要的资源,在运行过程中,系统内核和所有进程的运行都需要使用有限的物理内存,因此内存的分配和释放策略制约着系统的运行效率。高效的内存管理策略不仅要有效地管理系统内存,减少内存频繁分配,避免出现内存耗尽的情况,而且要尽量提高分配和回收的速度以提高系统的运行效率。

1 Linux内存管理模型

Linux系统的内存区域(zone)分为ZONE_DMA,ZONE_NORMAL和ZONE_HIGHMEM三种,系统给每种:on。都分配有buddysystem。在buddysystem中,物理内存空间是按2的整数次幂(称为。rder)放于zone少ee_area中的。系统会按照需求先拆分物理内存空间进行内存分配,再合并和释放内存,即在:oneallocator里调用。lloc_page()函数分配内存,调用free_page()函数释放内存。虽然buddysystem的效率非常高,但它存在内部碎片问题,这是因为只有从2的0次方到MAX_ORDER次方的页才会被分配出来,且对于硬件cache(缓存)来说,这种使用方法也不方便。在Linux内核中,固定分配的内存经常会被申请使用,如果每次申请都必须通过buddysystem就会浪费时间和空间,而引人slaballocator(分配器)则可以节省时间和空间。slaballocator模型图如图1所示。

slaballocato:会把内存资源放到cache里按定值进行缓存。如果系统需要使用内存,就可直接从此cache里调取,不使用时就释放,而内存也会被重新放回cache里。cache以slal)为单位来划分区域,几个连接的物理页常常包含在一个slab中。多个(ache在slaballocato:中共同维护,而每个cache里可能包含同一类型的。bject(对象)。系统通过调用kmalloc函数或kmem-cache_allot)函数分配slaballocato:中的内存资源,调用kfree()函数或kmem_cache_free()函数释放内存,如果在通过调用kmem_cache_allot)函数分配内存时。bject不在。ach。中,那么就通过调用cache_grow()函数在cache中增加一个slabcache_grow()函数给。bject分配物理内存(cache_grow()二>kmem_getpages(,而分配kmem_getpages还要通过buddysystem实现(kmem_getpages)二>alloc_pages_node()_

alloc_pages())。由此可见,slaballocator的出现并不意味着buddysystem完全消失,而是对后者的一种增强。

2  Linux伙伴系统

2.1 分配流程

(1)正常分配(或叫快速分配)

为提升性能,对分配的是单个页面的情况,系统会在每个内存管理区中都定义一个“perCPU”页框高速缓存。所有的“perCPU”高速缓存中都包含一些预先分配的页框,这些页框可以用来满足本地CPU发出的单个页内存请求。Linux内核为每个内存管理区和CPU都提供了两种高速缓存:一种是热高速缓存,它存放的页框中所包含的内容很可能在CPU硬件高速缓存中也存在;另一种是冷高速缓存。如果perCPU缓存中不存在页面,则可通过伙伴系统来提取页面进行增补。

对多个页面的分配,系统先分配指定类型的页面,若指定类型没有足够的页面,就转而分配链表中备用的类型,然后将类型链表保留下来。

(2)慢速(允许等待和页面回收)分配

慢速分配的一般流程是:唤醒内存页面回收线程、尝试低水位分配、忽略水位分配、压缩内存分配一直接回收内存分配一杀死线程分配(称为OOMkiller)压缩内存分配。

在Linux伙伴系统中,每个order都被分为五种不同的类型.它们被统称为MIGRATE_TYPES,即迁移类型。MIGRATE_TYPES是反碎片的一种机制,其原理是将伙伴系统的内存页分为可移动、不可移动和可回收等几种类型,同一类型的页只能放在同一个区域,如不可回收的页不能放在可移动类型区域。

MIGRATE一UNMOVABLE是不可移动页,在内存中有固定位置,不能移动,核心内核分配的大部分内存属于此类。MIGRATE_RECLAIMABLE是可回收页,不能移动,但可以删除,Kswapd内核线程在有交换页面需要时对此区域进行操作,如内存欠缺,Kswapd会将某些处于进程中的页面与,wap空间交换。MIGRATE_MOVABLE是可移动又可回收页,用户空间程序使用此类,通过页表映射实现,若应用程序虚拟地址空间有变化,只需变化页表即可。MIGRATE_RESERVE是在系统剩余内存很少且要求又比较紧急时才用到的区域。MIGRATE_ISOLATE在非一致内存访问NUMA(non-uniformmemoryaccess)架构上使用,它是一种特殊的虚拟区域,用于跨越NUMA节点移动物理内存页,系统不能通过这个区域申请内存。

图2是从内存为2GB的Linux系统中得到的内存分配信息。在图2中,前面几行是每个迁移类型可用内存的页数,最后一行是每个迁移类型的总页数〕

2.2 内存回收策略

(1)定期检查

系统的内存使用量是由kswapd进程定期检查的,kswapd进程在后台运行,当它检测到系统固定的阂值大于空闲的物理页面数时,系统就会进行页面回收。

(2)内存不足

在某些情况下,操作系统会突然需要通过伙伴系统为用户进程分配大量内存,或是需要新建一个较大的缓冲区。而此时若没有满足要求的物理内存。操作系统就需要尽快执行页面回收操作,释放出部分内存空间。这种页面回收方式也被称作“直接页面回收”,它采用页面回收算法(PFRA)oPFRA以获取页框并使它空余为目的,它根据页框所包含的内容而使用不同的处理方式。页框的内容分为不可回收页面、可交换页面、可同步页面和可丢弃页面。许多种属于进程的用户态、磁盘和高速缓存内存的页必须通过PFRA处理,处理时都根据试探法的几条准则进行。

系统在通过内存回收策略回收页面后也无法满足内存的需求时,会做出OOM(outofmemory)killer的决策。这是一种内存耗尽时管理内存的处理机制:操作系统会挑选正在运行中最恰当的一个进程,将其杀掉并将它所占用的页面全部释放。

内存回收机制主要依赖于pages_min,pages_low和pages_high三个字段。这三个字段在每个zon。的描述符中都有各自的定义:pages_min是区域预留的页面数目,pages_low是控制进行页面回收的最小阑值,pages_high是控制进行页面回收的最大阂值。如果pages_min大于空闲的物理页面数,那么系统运行会有较大的压力,需要进行页面回收。如果pages_low高于空闲的物理页面数,那么页面回收操作就会在系统内核中开始进行。pages_high低于空闲的物理页面数则是内存区域最理想的状态。

问题与解决方案

3.1 内存管理问题

系统在初始化时会根据内存的大小计算出一个回收内存的阂值,用来控制系统的空闲内存。17值越低,内存回收开始的越晚,空闲内存越小。其计算规则是:

min一ee_kbytes二sqrt(lowmem_kbytes*16)=4*sqrt(lowmem_kbytes)其中lowmem_kbytes是指系统内存大小〔)这种规则计算出来的阑值的范围为128K}64M。由于minfree_kbytes不是随着内存的增大而线性增大,因此也无需按线性预留出过多的内存,只要能保证系统的紧急使用量即可。

Linux为内存的使用设置了三种内存水位标记,watermark}high},watermark}low〕和watermark}min。它们所标记的含义分别为:剩余内存在high以上,表示内存剩余较多,目前内存使用压力不大;在high到高于low的范围内,表示目前剩余内存使用存在一定压力;在low到高于min的范围内,表示内存开始有使用压力,剩余内存不多;min是最小的水位标记,当剩余内存达到这个状态时,就说明使用面临很大压力。小于min的这部分内存是内核保留给特定情况使用的,一般不会分配。内存回收行为是基于剩余内存的水位标记进行决策的:当系统剩余内存低于watermark}to司的时候,内核的kswapd开始起作用,进行内存回收,直到剩余内存达到watermark}high〕的时候停止。如果内存消耗导致剩余内存达到或超过watermark}min,就会触发直接回收(directreclaim)o

min一ee_kl)yte、的主要用途是计算影响内存回收的三个参数watermark[min/low/high,等同于

page_min,page一ow和page_higho

page_min=watermark}min}=minfree_kbytes

page_low=watermark}low}=watermark}min}*5/4

page_high=watermark}high}-watermark}min}*3/2

min一ee_kbyte、的值设得越大,watermark的水平标记参数值越高,三个标记参数值之间的buffe:量也越大,这会使系统较早启动kswapd进行回收,且只有内存回收至watermark}high]时才会停止,导致系统预留过多空闲内存,降低了应用程序可使用的内存量。在极端情况下,min_free_kbyte、设置的值接近物理内存大小,就可能会导致因应用程序可用的内存太少而频繁地OOM。而min_free_kbyte、设得过小,则会导致系统预留内存过小。

kswapd回收的过程中也会有少量内存的分配行为标志PF_MEMALLOC,这是一个进程标志,这个标志可允许kswapd使用预留内存。被OOM选中杀死的进程在退出的过程中,如果需要申请内存也可以使用预留的内存。在以上两种情况下,使用预留内存可以避免系统进人(leadlock状态。

系统通过网络接收一段升级包后内存的变化如图4所示。在图4中,一段34M的mtd工具升级包被分为三个部分:rootf.bin,kernel.bin和app.bin。系统通过网络先接收:ootfs.bin,并以mallcorootfs.bin大小的内存存放它,再以fwrite的方式,将这块内存写人文件节点//tmp目录下,写完之后,再释放这块内存,然后将写完的//tmp/rootfs.bin通过烧写命令nandwrit。写人某个/mnt/mtdblock分区下。在nandwrite操作完成后,系统会删除:ootfs.bin并执行:m-rfrootfs.bin。接着,系统开始接收下一个升级包。pp.bin+kernel.bin,然后以(write方式将包含kernel.bin大小的内存写人//tmp目录下,再将kernel.bin写人nand分区节点下,之后释放掉kernel.bin。接下来再处理app.bin,处理方式是用fwrite先将app.bin写人挂载nand分区下,再对其进行解压。最后,系统删除。pp.bin,整个流程结束。

3.2 解决方案

在图4中,执行malloc(rootfs.bin)(在内存的动态存储区中分配一段连续空间)后,nr_free_pages会急剧减少,匿名内存页急剧增多,正在使用的匿名内存也跟着增多。执行fwrite时,nr_file_pages明显增加,说明内存中正在写人文件,执行free时剩余内存回升〔。可见,当Linux可使用的内存较小时,不能一次性malloc(分配)较大内存,以避免在剩余内存急剧减小到回收水位线时引发OOM事件。正确的做法应是多次malloc小内存,分批次执行(write,先将buffer写人//tmp目录下,再执行free,以使内存变化比较平滑。

在1Gb内存环境中,通过不断调整水位线(minfree_kbytes)的方式测试出剩余可用内存为29M左右,而在一次性读入文件到更新文件的过程中,29M内存是无法满足要求的,需要更改在线升级方案。更改的方案有两种:第一种是定时清理内存,在daemon_server中加人定时清理内存线程,并在需要升级时开启定时清理内存命令;第二种是更改升级时接收文件的机制。第二种方案因为在tcp接收更新文件时,不仅需要malloc与文件大小相同的内存,还需要执行fwrit。将mallo。出来的buffer写人/tmp目录下,而这一步也需要内存支持,增加了内存开销。图5为TCP接收更新文件时内存的变化图。在图5中,上述过程显示为在31s处出现一个突降。

由图5可知,第一次执行fwrite时,在15s处出现大突降,而在后面解压app.bin的过程中,内存一直维持在水位线上,因为总内存较小,所以设定水位线原始默认值为971K。据此,本文将内存malloc成小块,采用单个小块接收,接收完之后进行MDS校验,如果校验无误,再对每一小块都执行fwrite,将它们都写人到//tmp目录下,每成功写人一块,就free相应内存,这样不会造成内存突降,而且可增加系统运行的稳定性。

由以上分析可知,结合自刷新内存cache和改变mall二方式的方案可以使内存变化更为平缓,同时避免OOM事件发生。

结束语

本文讨论了一种Linux内存管理机制的方法,并给出优化结果。通过打patch补丁,修改内存管理器和设低内存水位标记,调整了内存消耗,避免了OOM事件发生。结合定时清理内存和改变内存分配,优化了内存使用,使内存变化更加缓和,提高了系统的稳定性。


相关推荐
联系我们

代写咨询
 362716231

发表咨询
 958663267


咨询电话

18030199209


查稿电话

18060958908


扫码加微信

weixin.png


支付宝交易

ali.jpg

  • 在线客服
  • 认准本站客服
  • 代写咨询
    362716231
  • 发表咨询
    958663267
  • 咨询电话
  • 18030199209
  • 查稿电话
  • 18060958908
  • 扫描加微信
  • 支付宝交易
  • 返回顶部
    在线客服