正如上图所示,上图有非常多的剩余空间,但因为内存碎片的问题,当系统需要申请4个内存页的时候,就无法申请内存了,虽然我们的内存空间里剩余内存的数量远远大于4个内存页,但无法找到连续的4个内存页,则会产生一个缺页异常。
而对于理想情况下的内存而言,应该如下图中的图例所示,对于一个程序,在其可用的内存地址空间内,不应该存在大片的不连续的内存,应该说,对于应用程序看到的内存区而言,总应该是连续的。
我们谈到内存碎片的时候,大多数只涉及到内核,因为对于内核而言,内存碎片确实是一个非常大的问题。虽然大多数现代的CPU都提供了巨型的页使用,但解决内存碎片依旧对内存使用密集型的应用程序有好处。在使用更大的页的时候,地址转换后备缓冲器只需处理较少的项,降低了TLB缓存失效的可能性。但巨型页的分配依旧需要连续的空闲物理内存。
反碎片
在2.6.24版本开发中,防止碎片的方法最终加入到内核,内核认为预防比治疗更加有效,所以内核使用反碎片(anti-fragmentation)的方法试图从最开始尽可能的防止碎片。
内核已经将已分配的页划分为以下3种类型:
- 不可移动的页:在内存中有固定位置,不能移动到其他地方,例如内核。
- 可回收的页:不能直接移动,但可以删除,其内容可以从某些源重新生成,例如映射自文件系统的数据。
- 可移动的页:可以随意地移动,属于用户空间和应用程序的页属于这个类别,它们是通过页表映射的,如果它们复制到新的位置,页表项可以相应的更新,而不会影响到应用程序。
页的可移动性依赖页属于以上3种类别中的哪一种,内核使用的反碎片技术基于将具有相同可移动性分组的思想。也就是说可移动的页和可移动的页具有相同的分组,相同,不可移动的页和不可移动的页具有相同的分组。
但要注意的是,从最初开始,内存并未划分成可移动页等不同移动性的不同的区,这些是在运行时行程的,内核的另一种方法确实将内存划分为不同的区,分别用于可移动页和不可移动页的分配。
内核使用一些宏来表示不同的迁移类
在内核想要分配不同的移动页时,如果对应链表为空,则后退到可回收页链表,接下来再到可移动页链表,最后到紧急分配链表。
虚拟可移动内存区.
###
依据可移动性组织页是防止物理内存碎片的一种可能方法,内核还提供了另一种组织该问题的手段,虚拟内存域ZONE_MOVABLE。这个机制和可移动性分组框架相比,ZONE_MOVABLE必须由管理员显式激活。
ZONE_MOVABLE的基本思想很简单,可用的物理内存划分为两个内存域,一个用于可移动分配,一个用于不可移动分配。这会自动防止不可移动页向可移动内存域引入碎片。
不过这也会造成另一个问题,内存如何在两个竞争的区域之间分配可用内存?这显然对内核要求太高,所以管理员必须做出决定。这个数据结构是我们非常熟悉的zone_type数据结构。