Linux内存管理复习总结

首先来看一张图:

这张图就是Linux分配内存的大致流程。下面我来总结一下。

分页

首先Linux是基于内存管理采用分页机制,内核代码中它将所有段基址都设置为0,Linux采用这样的方法直接避过了分段机制。仅仅用分段来控制用户态和用户态的访问权限。

内核内存分配

内核对于大块内存的分配基于伙伴算法,用来解决外部碎片的问题。伙伴算法最低分配的单位是一页。在物理内存的每个Zone中都有一个free_area[]数组,分别存储2的幂的页面。伙伴算法就是比如说申请8个页面,然后首先去查找free_area[3]有没有可用的8个页面,如果没有就将上一级16个页面一分为二,一部分分配出来,另一部分重新加入到free_area数组对应8个页面的位置。当内存释放时,这两个8个页面又会重新合并。(这种互逆的操作将最大力度减小碎片的产生)。

伙伴算法是基于一页分配的,内核中对于远小于一页的字节级别内存,比如task_struct结构体,使用伙伴算法就会产生内部碎片。

为了解决内部碎片,Linux引入了slab机制。

slab机制

内核通常会对某些小对象频繁进行分配,slab分配器通过对类似对象大小的缓存提供这个功能。

slab分配器类似于一个全局的对象池。可以缓存不同大小的对象,最小一个缓存行大小,最大则是128k。slab分配器有三层结构,分别是per-CPU的缓存对象,CPU间共享的缓存对象,每个NUMA节点共享的slab页面。为了避免自旋锁的竞争,内核分配缓存对象优先从per-CPU数组中获取,并且获取数组最热的对象。因为最热的对象可能还在L1 cache中。如果per-CPU数组中没有对象分配,则回去CPU共享的shead数组中查找对象,如果还没有,则会去针对NUMA节点的slab三个链表中查找。这三个链表是slab满链表,slab部分满链表,slab空链表。分配对象从slab部分满链表中查找,如果部分满链表中所有对象都分配出去了,则会将它加入slab满链表之中。如果slab部分满和空链表都没有了,则会调用get_freepage()从伙伴系统分配2的幂的页面。

slab机制实际上就是kmalloc的底层实现。

如果内核需要分配不连续的内存,那么会调用vmalloc,vmalloc建立内核虚拟内存对物理存储器的页面映射,但由于vmalloc向伙伴系统要要内存不连续,所以相对kmalloc效率会低一些。vmalloc分配时使用__GFP_HIGHMEM标志,优先从高端内存获取物理页。

vmalloc是对内核虚拟内存的映射,和进程内存分配类似,因使用缺页中断的机制,下面会说到。

进程的内存分配

创建进程fork(),动态内存malloc()都涉及到进程的内存分配。操作系统对于进程的内存分配,以mmap为例。malloc对于大于128k的内存使用mmap分配,mmap底层调用do_mmap(),由于是匿名映射,传入file指针为NULL,然后会选择调用当前进程的current->mm->get_unmapped_ared,在进程的虚拟地址空间分配一个VMA区域,并将该新的VMA加入到mm_struct管理的VMA链表和红黑树中。此时,内核并不为进程分配实际的物理页面(页表项标记不在内存)。当用户进程第一次访问这片内存时,虚拟地址经过MMU转换,通过页目录查找到相应页表项,页表项中标志表明对应页不再内存中。则触发缺页中断。由于是匿名映射,内核在内存中找到一块牺牲页,将牺牲页换出内存,将内存中该页的位置清零,并修改相应页表项。然后重启引发缺页中断的指令,这时相应页面已经在内存中了,进程就可以正常使用内存了。

参考:

  1. linux内核—–内存管理相关技术
  2. linux内存管理总结之内存分配
  3. Linux内存管理机制 buddy伙伴算法
  4. linux内存管理–缺页异常处理
  5. linux缺页异常剖析–用户空间
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值