一 linux内存管理以及内存碎片产生原因
最底层使用伙伴算法管理内存页面。系统将所有空闲内存页面分10个组,每个组中的内存块大小依次是1,2,4……512个内存页面,每组中的内存块大小相
同,并且以链表结构保存。大小相同,并且内存地址连续的两个内存块称为伙伴。伙伴算法的中心思想就是将成为伙伴的空闲内存合并成一个更大的内存块。
os中使用get_free_page获取空闲页面,如果找不到合适大小的空闲页面,则从更大的组中找到空闲内存块,分配出去,并将剩余内存分割,插入到
合适的组中。当归还内存时,启动伙伴算法合并空闲内存。如果不停的申请内存,并且部分归还,但归还的内存不能成为伙伴,长期运行后,所有内存将被分割成不
相邻的小块,当再次申请大块内存时,则可能由于找不到足够大的连续内存块而失败,这种零散的不相邻的小块内存称之为内存碎片。当然这只是理论上的说明,伙
伴算法本身就是为了解决内存碎片问题。
二 malloc子系统内存管理(dlmalloc)
应用层面的开发并不是直接调用sbrk/mmap之类的函数,而是调用malloc/free等malloc子系统提供的函数,linux上安装的大多为
DougLea的dlmalloc或者其变形ptmalloc。下面以dlmalloc为例说明malloc工作的原理。
1 dlmalloc下名词解释:
boundary tag: 边界标记,每个空闲内存块均有头部表识和尾部标识,尾部表识的作为是合并空闲内存块时更快。这部分空间属于无法被应用层面使用浪费的内存空间。
smallbins: 小内存箱。dlmalloc将8,16,24……512大小的内存分箱,相临箱子中的内存相差8字节。每个箱子中的内存大小均相同,并且以双向链表连接。
treebins: 树结构箱。大于512字节的内存不再是每8字节1箱,而是一个范围段一箱。比如512~640, 640~896…..每个箱子的范围段依次是128,256,512……。每箱中的结构不再是双向链表,而是树形结构。
dv chunk: 当申请内存而在对应大小的箱中找不到大小合适的内存,则从更大的箱中找一块内存,划分出需要的内存,剩余的内存称之为dv chunk.
top chunk: 当dlmalloc中管理的内存都找不到合适的内存时,则调用sbrk从系统申请内存,可以增长内存方向的chunk称为top chunk.
2 内存分配算法
从合适的箱子中寻找内存块–>从相临的箱子中寻找内存块–>从dv chunk分配内存–>从其他可行的箱子中分配内存–>从top chunk中分配内存–>调用sbrk/mmap申请内存
3 内存释放算法
临近内存合并–>如属于top chunk,判断top chunk>128k,是则归还系统
–>不属于chunk,则归相应的箱子
dlmalloc还有小内存缓存等其他机制。可以看出经过dlmalloc,频繁调用malloc/free并不会产生内存碎片,只要后续还有相同
的内存大小的内存被申请,仍旧会使用以前的合适内存,除非大量调用malloc之后少量释放free,并且新的malloc又大于以前free的内存大
小,造成dlmalloc不停的从系统申请内存,而free掉的小内存因被使用的内存割断,而使top
chunk<128k,不能归还给系统。即便如此,占用的总内存量也小于的确被使用的内存量的2倍(使用的内存和空闲的内存交叉分割,并且空闲的内
存总是小于使用的内存大小)。因此可以说,在没有内存泄露的情况,常规频繁调用malloc/free并不会产生内存碎片。
posted on 2010-08-25 15:09
何克勤 阅读(331)
评论(0) 编辑 收藏 所属分类:
GNU Linux/Unix