1.Linux内存管理的主要内容
a. 虚拟内存管理
b. 内核空间内存管理
c. 用户空间内存管理
2.虚拟内存和物理内存映射
ZONE_HIGHMEM的主要作用:通过非永久映射实现内核对896M之外的物理内存的访问,比如:实际物理内存为4G,内核直接映射了896M,之外的897M-4G内核都无法访问是无法接受的。
3.内核内存管理的目标
a.最小化管理内存所需的时间
b.最大化用于一般应用的可用内存
4.内存分页:连续内存和分散内存的取舍
Linux内核管理物理内存是通过分页机制实现的,它将整个内存划分成无数个4k(在i386体系结构中)大小的页,从而分配和回收内存的基本单位便是内存页了。
利用分页管理有助于灵活分配内存地址,因为分配时不必要求必须有大块的连续内存,系统可以东一页、西一页的凑出所需要的内存供进程使用。
虽然如此,但是实际上系统使用内存时还是倾向于分配连续的内存块,因为分配连续内存时,页表不需要更改,因此能降低TLB的刷新率(频繁刷新会在很大程度上降低访问速度)。
====>也就是说,分页机制可以实现分散的物理页的使用,为什么对连续内存的需求还是这么强烈?还是时间和效率的问题。
5.内核内存分配策略和伙伴系统
分配器主要是基于堆策略,堆就是大块内存,当用户申请内存时分配器采用的两种策略进行搜索:
a.fast-fit:找到第一块满足要求的内存就分配给用户
优点:快速,用户使用内存的效率比较高,因为很快就有回应
缺点:由于各个使用者并不是按顺序归还内存的,因此造成内存之间存在空洞,我们也称为外部碎片;
b.best-fit:找到最合适的一块
典型分配器:buddy memoryallocation
解决的痛点:a.内存分配:将内存分为2的N次幂个区,单页或者特定页1/2/4/8...512,使用best-fit思想来响应内存请求;
b.内存归还:当内存被归还之后,查看相邻区域是否也有未使用内存,进行合理的合并,小块变大块;
存在的缺陷:内核中的使用经常是诸如:文件描述符/进程描述符等等小于或者说远小于4K的内存需要,因此产生内部碎片;
====>无论是best-fit还是fast-fit都是围绕着管理时间最小化和使用内存效率最大化两个角度展开的,说到底还是时间和空间的权衡。
6.slab分配器的产生
Linux 所使用的 slab 分配器的基础是 JeffBonwick 为 SunOS 操作系统首次引入的一种算法,Jeff 的分配器是围绕对象缓存进行的,在内核中,会为有限的对象集(例如文件描述符和其他常见结构)分配大量内存,Jeff 发现对内核中普通对象进行初始化所需的时间超过了对其进行分配和释放所需的时间,Jeff 的结论是不应该将内存释放回一个全局的内存池,而是将内存保持为针对特定目而初始化的状态。
Linux slab 分配器使用了这种思想和其他一些思想来构建一个在空间和时间上都具有高效性的内存分配器。
====>slab分配器主要是针对那些内核中小但是多而频繁的内存需求的申请和释放的特征入手,做的局部物理页的优化策略,提高效率降低时间,还是时间和空间。
7.slab分配器的组织形式、分配和回收策略
a.slab和buddy的关系
从一定程度上来说,slab分配器是依托于buddy系统的,slab会先从buddy那里分配多个连续的内存页,这些页就是slab范围内实施slab机制的原材料。
b.slab机制的组织形式
1.cache_chain和kmem_cache
在最高层是 cache_chain,这是一个 slab 缓存的链接列表,这对于 best-fit 算法非常有用,可以用来查找最适合所需要的分配大小的缓存(遍历列表),
cache_chain 的每个元素都是一个 kmem_cache 结构的引用(称为一个cache),它定义了一个要管理的给定大小的对象池。
可见:slab分配器内部使用了和buddy一样的best-fit策略,kmem_cache就是大小不一样的单个或多个内存页。
2.slabs链表和slab的扩展
每个缓存都包含了一个 slabs 列表,这是一段连续的内存块(通常都是页面),
存在 3 种 slab:
slabs_full-------完全分配的 slab
slabs_partial----部分分配的 slab
slabs_empty------空slab,或者没有对象被分配
slab 列表中的每个 slab 都是一个连续的内存块(一个或多个连续页),它们被划分成一个个对象object,
这些对象是从特定缓存中进行分配和释放的基本元素。
注意 slab 是 slab 分配器进行操作的最小分配单位,因此如果需要对 slab 进行扩展,这也就是所扩展的最小值,通常来说,每个 slab 被分配为多个对象。
3.slab分配策略
举例说明:如果有一个名叫inode_cachep的structkmem_cache节点,它存放了一些inode对象。当内核请求分配一个新的inode对象时,slab分配器就开始工作了:
a.首先要查看inode_cachep的slabs_partial链表,如果slabs_partial非空,就从中选中一个slab,返回一个指向已分配但未使用的inode结构的指针。完事之后,如果这个slab满了,就把它从slabs_partial中删除,插入到slabs_full中去,结束;
b.如果slabs_partial为空,也就是没有半满的slab,就会到slabs_empty中寻找。如果slabs_empty非空,就选中一个slab,返回一个指向已分配但未使用的inode结构的指针,然后将这个slab从slabs_empty中删除,插入到slabs_partial(或者slab_full)中去,结束;
c.如果slabs_empty也为空,那么没办法,cache内存已经不足,只能新创建一个slab了。
4.slab回收策略
slabs_empty中的内存是优先被回收的。
5.slab分配器的优点
a.减小了内存碎片化
b.提高了系统的效率,
当对象拥有者释放一个对象后,SLAB的处理是仅仅标记对象为空闲,并不做多少处理,而又有申请者申请相应大小的对象时,SLAB会优先分配最近释放的对象,这样这个对象甚至有可能还在硬件高速缓存中,有点类似管理区页框分配器中每CPU高速缓存的做法。
===>无论是buddy还是slab根本目的都是降低时间提高效率,为了实现时间和空间的权衡,需要从内存组织形式、分配策略、回收策略三个角度出发。
8.金钱理论
fast-fit:手头有钱就给,但是归还不一定能凑出再次需要的内存
buddy:把手头有的钱分为不同面值,根据需求给出最合适的面值,当有归还时凑够了零钱就换个整钱
slab: 每次都要一点点但是要的频率很高,索性给出一定数量,让其自己的分配器分配,再将有支配权的这些钱也分成更小的面值,best-fit分配
归还时也是给自己的分配器,并且重复使用,当凑够一定数量空闲的钱就归还给上级分配器;
====>这个是我胡诌的,需要一个实际生活中的例子去模拟buddy和slab的机制,我觉得还不错^_^
http://www.cnblogs.com/tolimit/p/4566189.html
http://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/
http://www.cnblogs.com/wangzahngjun/p/4977425.html
http://ilinuxkernel.com/?p=1013
http://lib.csdn.net/article/linux/32887