Linux 内存管理
侯捷老师的视频G2.9std alloc
部分我们可以理解内存分配器是如何管理内存的。也就是维护一些具有固定内存大小的自由链表。如有分配需求就将其取下链表分配出去。如果不够就再调用malloc
进行申请。然后进行切割。
这里的内存管理依旧是比较上层的。我们后来也提到了malloc
会使用libc的C运行时库里面的mmap
系统调用和brk
系统调用进行分配内存分配。大内存使用mmap
,小内存使用brk
。malloc
内部就是一个类似于std alloc的内存池机制但是更为复杂。但是这里所有的分配都是分配的虚拟内存。只有当分配后我们真正访问了这部分内存,然后触发缺页中断后才会真正分配物理内存给我们。
这个时候我们可以继续深入探讨。那么mmap
和brk
又是如何分配的?这里就是使用了伙伴系统算法(buddy)和slab机制。这里就真的是进行物理内存的分配了。
buddy系统算法
在我个人理解中,这个依旧非常像std alloc
部分。
伙伴系统算法(Buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。每个页框块的第一个页框的物理地址是该块大小的整数倍。
- 假设要申请一个256个页框的块,先从256个页框的链表中查找空闲块,如果没有,就去512个页框的链表中找,找到了则将页框块分为2个256个页框的块,一个分配给应用,另外一个移到256个页框的链表中。如果512个页框的链表中仍没有空闲块,继续向1024个页框的链表查找,如果仍然没有,则返回错误。页框块在释放时,会主动将两个连续的页框块合并为一个较大的页框块。
- 这部分和
std alloc
几乎是一个原理。
- 这部分和
- 从上面可以知道Buddy算法一直在对页框做拆开合并拆开合并的动作。Buddy算法牛逼就牛逼在运用了世界上任何正整数都可以由2^n的和组成。这也是Buddy算法管理空闲页表的本质。
- Buddy 系统解决了物理内存分配的外部碎片问题。
slab
- 在Linux中,伙伴系统(buddy system)是以页为单位管理和分配内存。但是现实的需求却以字节为单位,假如我们需要申请20Bytes,总不能分配一页吧!那岂不是严重浪费内存。那么该如何分配呢?slab分配器就应运而生了,专为小内存分配而生。slab分配器分配内存以Byte为单位。但是slab分配器并没有脱离伙伴系统,而是基于伙伴系统分配的大内存进一步细分成小内存分配。
- 这部分是不是非常像
mmap
和brk
之间的关系?
- 这部分是不是非常像
slab分配需要解决的是内存的内部碎片问题。
- 所谓内部碎片就是指被内核分配出去但是不能被利用的内存。
而外部碎片是指由于频繁地申请和释放页框而导致的某些小的连续页框,比方只有一个页框,无法分配给需要大的连续页框的进程而导致的内存碎片。
- kmem_cache是链接在一起形成一个全局的双向链表。可以理解为一个内存池。每个内存池包含了一个slabs的链表,这通常是一段连续的内存块。
- slab是slab分配器的最小单位,在实现上一个slab有一个或多个连续的物理页组成(通常只有一页)。单个slab可以在slab链表之间移动,例如如果一个半满slab被分配了对象后变满了,就要从slabs_partial中被删除,同时插入到slabs_full中去。
- object是内存池中提供的内存的单位。也就是对象。
- 存在3种slab:
- slabs_full(完全分配的slab)
- slab 中的所有对象被标记为使用。
- slabs_partial(部分分配的slab)
- slab 中的对象有的被标记为使用,有的被标记为空闲。
- slabs_empty(空slab,或者没有对象被分配)。
- slab 中的所有对象被标记为空闲。
- slabs_full(完全分配的slab)
为了进一步解释,这里举个例子来说明,用struct kmem_cache结构描述的一段内存就称作一个slab缓存池。一个slab缓存池就像是一箱牛奶,一箱牛奶中有很多瓶牛奶,每瓶牛奶就是一个object。分配内存的时候,就相当于从牛奶箱中拿一瓶。总有拿完的一天。当箱子空的时候,你就需要去超市再买一箱回来。超市就相当于partial链表,超市存储着很多箱牛奶。如果超市也卖完了,自然就要从厂家进货,然后出售给你。厂家就相当于伙伴系统。
- 个人理解。slab也是一种池化思想,依旧是比较直观的内存池思想,也就是内存池主动维护一块内存,有小块内存则通过小块的分配方法分配出去,交还的时候归还给内存池而不是操作系统。
slab和buddy之间的关系 – 互补关系
slab系统与buddy系统所要解决的问题是互补的,一个解决外部碎片一个解决内部碎片,slab是依赖buddy系统的。因为所有的内存都需要伙伴系统来分配,只不过是小块内存的时候通过slab来进行更细的划分。
- PS: std alloc。是不是非常像?