转载本文请联系大家是极客公众号。pageframeallocator包括慢速分配中的内存碎片和内存回收,代码如下:staticinlinestructpage*__alloc_pages_slowpath(gfp_tgfp_mask,unsignedintorder,structalloc_context*ac){page=__alloc_pages_direct_compact(gfp_mask,order,alloc_flags,ac,INIT_COMPACT_PRIORITY,&;。..page=__alloc_pages_direct_reclaim(gfp_mask,order,alloc_flags,ac,&did_some_progress);...}对于空间设计,这次只讲内存碎片整理,以后再讲内存回收什么是内存碎片Linux物理内存碎片包括内部碎片和外部碎片两种,内部碎片:是指分配给用户的内存空间中未使用的部分,比如一个进程需要使用3K字节的物理内存,所以向系统申请内存相等到3K字节,但是由于Linux内核伙伴系统算法的最小粒度是4K字节,所以它分配了4K字节的内存,并且1K字节的未使用内存是内存碎片。外部碎片:指系统中无法使用的小内存块。例如,剩余系统内存为16K字节,但是16K字节内存是由4个4K字节的页组成的,即16K内存的物理页框号#1是不连续的。在系统剩余16K字节内存的情况下,系统无法成功分配大于4K的连续物理内存,这是out-of-memoryfragmentation造成的。碎片整理算法Linux内存碎片整理算法主要应用了内核的页面迁移机制,即迁移可移动页面后释放连续物理内存的方法。假设有一个非常小的内存域如下:蓝色表示空闲页面,白色表示已经分配的页面。可以看到上面内存域中的空闲页面(蓝色)非常碎片化,无法分配大于两个页面的连续物理内存。.下面演示内存正则化的简化工作原理。内核会运行两个独立的扫描动作:第一次扫描从内存域底部开始,扫描时将分配的可移动(MOVABLE)页记录到一个列表中:另外,第二次扫描从内存域顶部开始,扫描可以作为页面迁移目标的空闲页面位置,然后记录在一个列表中:当两次扫描在域中间相遇时,表示扫描结束,再扫描左边将得到的分配页迁移到右边的空闲页,左边形成连续的物理内存,完成页正则化。碎片化整理的三种方式staticstructpage*__alloc_pages_direct_compact(gfp_tgfp_mask,unsignedintorder,unsignedintalloc_flags,conststructalloc_context*ac,enumcompact_priorityprio,enumcompact_result*compact_result){structpage*page;unsignedintnoreclaim_flag;if(!order)returnNULL;noreclaim_flag=memalloc_noreclaim_save();*compact_result=try_to_compact_pages(gfp_mask,order,alloc_flags,ac,prio);memalloc_noreclaim_restore(noreclaim_flag);如果(*compact_result<=COMPACT_INACTIVE)返回NULL;count_vm_event(COMPACTSTALL);page=get_page_from_freelist(gfp,acage)_ag,或{structzone*zone=page_zone(page);zone->compact_blockskip_flush=false;compaction_defer_reset(zone,order,true);count_vm_event(COMPACTSUCCESS);returnpage;}count_vm_event(COMPACTFAIL);cond_resched();returnNULL;}这也是上面内存的代码实现压实算法。在Linux内核中有三种碎片整理方法。我们总结如下:这里不分析源码。有了宏观的认识,不难在网上搜索到具体的实现细节。OK,我们进入下面这篇文章的内容:内存回收(memoryreclaim)。
