1、伙伴系统alloc_pages

1.伙伴系统是基于zoom来管理分配的。

2.分配的最小的单位就是一个page就是(4k),不同的系统还可以设置成(16k),最大能分配的内存块是max_order(11),就是4M物理页面。

3.内存在初始化的时候,会计算出zoom对应的3个水位值分别是watermark high,low,min。

4.zoom数据结构里有free_area数据结构,分别对应order从0~10的不同的内存块,free_area又细分不同的迁移类型:有Moveable(用户态malloc的页面就是可迁移类型),UnMoveable(内核分配的页面一般都是不可迁移类型),ReCliantable(文件映射,可以回写磁盘的页面),linux系统刚刚初始化完成之后,基本都是在order等于10,并且是Moveable的那个大内存链表中。

5.alloc_pages(gfp_mask,order)gfp_mask==>低4个bit可以看出从哪个zoom优先分配---HighMem-Zoom,还是Normal-zoom。其他bit可以GFP_KERNEL、GFP_USER=====>都有可能引起进程睡眠,GFP_ATOMIC=====>高优先级的,不会引起睡眠 。

6. zone_watermark_ok=====》检查水位是否满足要求。

7.buffered_rmqueue
    1)内存大多数情况下都是order等于0的时候,每个cpu有个单叶匡的高速缓存,直接从单叶匡的高速缓存中分配。
    2)order大于0的话,rmqueue去分配内存。根据gfp_mask分配掩码找到free_area中的freelist,从order开始寻找,依次++,直到找到空闲的大内存块,然后需要把多余的内存块进行expand切割,加入到小order的freelist里面。

8.alloc_free释放函数
        判断相邻的内存块是不是伙伴:1.大小相同2.地址连续3.从同一个大块中切割出来的。才能合并成一个大内存。

2、buffered_rmqueue

单页框的情况:
        1)直接从本地cpu的页框高速缓存中分配,每个cpu都有一个独立的缓存池。
        2)不需要申请zoom->lock这个锁。
        3)不需要再进行内存块的切割操作,因为一开始的已经分配好了。
        order==0的时候,从zoom区域的pageset高速缓存页里面分配,pcp = &this_cpu_ptr(zone->pageset)->pcp;pcp里面有空闲页面的话,直接分配。如果没有的话,也是调用__rmqueue从伙伴系统中分配。
        order大于0的时候,才会__rmqueue从伙伴系统中分配。

        spin_lock_irqsave(&zone->lock, flags);page = __rmqueue(zone, order, migratetype);spin_unlock(&zone->lock);

3、__rmqueue

1)从alloc_pages参数里的order对应的free_area开始寻找,对应的迁移类型为空的话,就往上找一个,order++。
2)直到找到不为空的free_area,对于的order。把对应的内存page从free_list里面删除。
3)取出这个内存快,还需要把剩下的切割(expand),把剩下的内存块加入到order的free_list链表中去。

4、slub机制:

1.伙伴系统能分配的最小的内存是4k,内存使用slab机制来分配小段内存。
2.slub,slob都是slab的一种,是在slab基础上的优化,现在内核基本都使用slub机制,slub相比slab没有color着色区,还有空闲、部分空闲、满链表。主要的结构体定义、还有分配的接口都是兼容的。
3.slub分配内存主要4个接口:
        kmem_cache_create/创建slab缓存,并不实际分配slab对象
        kmem_cache_alloc/才会去真正分配一个slab对象
        kmem_cache_free
        kmem_cache_destroy
4.slab缓存的描述符kmem_cache的重要成员:
    1)struct kmem_cache_cpu __percpu *cpu_slab;//指向本地CPU缓冲池
        本地cpu缓存池:1.freelist成员指向第一个可用内存obj首地址
                      2.page成员指向当前slab所使用的page页面
                      3.partial链表,本地cpu缓存的一些空闲slab
    2)kmem_cache_node 缓存节点:1.也有一个partial联系,所有cpu的共享的空闲slab链表。2.自旋锁3.当前kmem_cache_node的slab的数量。

5.kmem_cache_create
        分配一个kmem_cache缓存池对象,这个对象也是用slub分配的。====>就像函数要调用自己来创建自己,kmem_cache_init()函数,静态定义第一个kmem_cache(static struct kmem_cache boot_kmem_cache;)该kmem_cache就是为了kmem_cache_create()函数创建kmem_cache结构体的slab缓存池。
        1)初始化object size(实际size加上align对齐)。
        2)根据object 的size大小,来算一个slab需要多少个页面,就是order值。还有一个slab中能包含多少object。需要的页面的页面order和能包含多少object保存在oo成员里面,order_object。
        3)offset:slub分配在管理object的时候采用的方法是:既然每个object在没有分配之前不在乎每个object中存储的内容,那么完全可以在每个object中存储下一个object内存首地址,就形成了一个单链表。很巧妙的设计。那么这个地址数据存储在object什么位置呢?offset就是存储下个object地址数据相对于这个object首地址的偏移。
        4)分配per cpu的缓存对象,kmem_cache_node节点。
        5)主要就初始化一些kmem_cache缓存的一些成员,并不实际分配内存,也不分配slab对象。

6.kmem_cache_alloc
    1)刚创建的kmem_cache缓存,第一次分配slab对象的时候,本地CPU的缓存和共享的缓存node节点的partial链表都是空的。
    2)就需要通过伙伴系统alloc_pages来分配页面,freelist执行page的地址,page赋值当前正常使用的page,重要的一步就是:遍历page内存大小来划分object大小,就是在每个object内部的offset地址来存储下一个object的地址,这样就形成了一个单链表。
    3)分配完page之后,就freelist直接分配一个object,freelist指向单链表的以一个object地址,下次分配的时候,链表不为空的话,还直接分配。
    4)首先从cpu 本地缓存池分配,如果freelist不存在,就会转向per cpu partial分配,如果per cpu partial也没有可用对象,继续查看per node partial,如果很不幸也不没有可用对象的话,就只能从伙伴系统分配一个slab了,并挂入per cpu freelist。

7.kmem_cache_free
    1)slab释放,slab里面维护了一个单链表,新释放的object对象,也需要加入到这个单链表中去。===》1.让被释放的obj的set地址存储freelist值。2.freelist指向新的object。
    2)obj属于的page就是当前使用的page,那么就直接释放。需要判断释放是满slab,需要挂入到本地cpu的partial链表,page数据结构体里面也有个freelist专门用来slab机制,用page里面的freelist来指向新的object地址。
    3)需要额为判断的是:本地CPU的空闲的slab大于一定数目后,需要转移一些到共享的node里面,如果kmem_cache_node节点中空闲的slab数量大于一定后,需要往伙伴系统中释放。per cpu partial链表管理的所有slab的free object数量超过kmem_cache的cpu_partial成员的话,就需要将per cpu partial链表管理的所有slab移动到per node partial链表管理。

kmalloc:
1)是内核用来分配内存的接口,就是基于slab机制实现。
2)分配的size大于4k的话,还是kmalloc_large在伙伴系统中分配,小于4k的话,kmalloc_slab是slab分配。
3)系统中专门为kmalloc申请了一系列大小的kmem_cache缓冲区,分别对应8字节、16字节、32、字节的slab缓存池。
4)找到对应的kmem_cache后,就是通过slab来分配释放内存。

5、malloc

1)内存布局
        栈自顶向下扩展,推至第向上扩展,mmap区域也是至顶向下。

2)glibc库
        malloc和free都是glibc封装的用户态函数,来动态分配和释放内存。
        malloc底层是通过brk、mmap系统调用来申请内存,每次都通过系统调用来申请的内存会影像性能。为了保持高效的分配, allocator 一般都会预先分配一块大于用户请求的内存, 并通过某种算法管理这块内存. 来满足用户的内存分配要求, 用户 free 掉的内存也并不是立即就返回给操作系统。

3)为什么需要glibc而不直接brk,或者mmap分配内存?
        brk、mmap都是系统调用,都要从用户态切换到内核台,频繁的小内存申请、释放会增加系统的负担。glibc采用了内存池的设计,每次先从内存池中申请、没有的话再向内核申请。分配内存 < DEFAULT_MMAP_THRESHOLD(128k),走__brk,从内存池获取,失败的话走brk系统调用 
分配内存 > DEFAULT_MMAP_THRESHOLD,走__mmap,直接调用mmap系统调用。

4)内存池保存在bins这个长128的数组中,每个元素都是一双向个链表。其中bins[0]目前没有使用
bins[1]的链表称为unsorted_list,用于维护free释放的chunk。bins[2,63)的区间称为small_bins,用于维护<512字节的内存块,其中每个元素对应的链表中的chunk大小相同,均为index*8。
bins[64,127)称为large_bins,用于维护>512字节的内存块,每个元素对应的链表中的chunk大小不同,index越大,链表中chunk的内存大小相差越大,例如: 下标为64的chunk大小介于[512, 512+64),下标为95的chunk大小介于[2k+1,2k+512)。同一条链表上的chunk,按照从小到大的顺序排列。

5)do_brk
do_brk仅进行匿名映射,申请从addr开始len大小的虚拟地址空间。
do_brk首先判断虚拟地址空间是否足够,然后查找VMA插入点,并判断是否能够进行VMA合并。如果找不到VMA插入点,则新建一个VMA,并更新到mm->mmap中。

6)VM_LOCK标志位
会立即建立和物理页面的映射,按照PAGE_SIZE为步长
__mlock_vma_pages_range
    ====>__get_user_pages

linux内存管理简单总结相关推荐

  1. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  2. 万字长文,别再说你不懂Linux内存管理了(合辑),30 张图给你安排的明明白白...

    之前写了两篇详细分析 Linux 内存管理的文章,读者好评如潮.但由于是分开两篇来写,而这两篇内容其实是有很强关联的,有读者反馈没有看到另一篇读起来不够不连贯,为方便阅读这次特意把两篇整合在一起,看这 ...

  3. 别再说你不懂Linux内存管理了,10张图给你安排的明明白白!

    来自:后端技术学堂 过去的一周有点魔幻,有印象的有三个新闻:天猫总裁绯闻事件,蘑菇街裁员,不可能打工的周某也放出来了.三件事,两件和互联网行业相关,好像外面的世界很是精彩啊!吃瓜归吃瓜,学习还是不能落 ...

  4. Linux内存管理原理【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...

  5. Linux内存管理【转】

    转自:http://www.cnblogs.com/wuchanming/p/4360264.html 转载:http://www.kerneltravel.net/journal/v/mem.htm ...

  6. Linux内存管理原理

    本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...

  7. Linux 交换内存空间原理(swap)(Linux内存管理)(cgroups)

    文章目录 什么是swap? 为什么需要swap? swap的缺点? 到底要不要swap? 内存不够用 内存勉强够用 内存充裕 桌面环境 服务器环境 swap大小配置多少比较合适? 怎么配置swap? ...

  8. 闲聊Linux内存管理(1)

    今天还有时间,之前一直想抽时间来写写Linux内核原理相关的东西,关注点不在代码,而在于内在的原理和机制,让大家对Linux内核有个总体的感性认识,个人认为这很有必要,把看似复杂.深不可测的内核实现, ...

  9. Linux内存管理(经典)

    今天来带大家研究一下Linux内存管理.对于精通 CURD 的业务同学,内存管理好像离我们很远,但这个知识点虽然冷门(估计很多人学完根本就没机会用上)但绝对是基础中的基础,这就像武侠中的内功修炼,学完 ...

最新文章

  1. Android Json解析方法
  2. Python学习笔记十 IO编程
  3. 仅支持chrome的滚动条样式
  4. 百分点宣布完成C轮融资2500万美元 将进一步开放云平台应用
  5. DS-5/RVDS4.0变量初始化错误
  6. python和halcon_VisionPro和Halcon的详细对比
  7. 预定义变量$_SERVER
  8. 40款精简活力fcpx标题字幕 mTitle Kinetic for Mac
  9. 会买单吗?李楠创办的怒喵科技发布新品牌了,推出潮流无线桌面产品
  10. FreeDroid开发过程中遇到的一些问题
  11. php常用设计模式和算法,常用算法、问答、设计模式
  12. 技术支持诈骗手段翻新:借勒索软件类锁屏界面恐吓用户
  13. fcpx瘦身插件_FCPX有哪些特别好用的插件?
  14. java 开源框架集
  15. 计算机后端维护,机房智能交通后台系统运行维护内容.doc
  16. 卡诺图化简及逻辑函数的规范范式:SOP与POS形式
  17. 艾里斑大小与像元尺寸的匹配问题
  18. A股各概念板块龙头股大全
  19. cad隐藏图层命令快捷键_CAD关闭图层快捷键,隐藏显示的CAD图层
  20. 黑客组织“洋葱狗”潜伏3年终曝光 定期偷袭能源及交通行业

热门文章

  1. 计算机指数表示,e是什么
  2. Win11找不到本地用户和组怎么办
  3. LoRa技术的基本认识
  4. dayz正版服务器在哪,我的世界1.7.2服务器末日生存DayZ模式
  5. OpenCV计划推出三代OAK相机
  6. scrapy创建项目详解---HtmlXPathSelector
  7. 高精度电子罗盘的应用场景
  8. HCIE课程笔记17-VLAN配置
  9. Gabor滤波器学习 综合多篇关于Gabor滤波器的博客总结
  10. 算法题_位运算_4_是不是2的整数次方