linux内存管理简单总结

news/2025/1/18 10:42:15/

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
 


http://www.ppmy.cn/news/476191.html

相关文章

Linux内核之内存管理知识结构

目录 Linux内核源码分析架构图 一、虚拟内存地址空间布局 1、用户空间 2、内核空间 3、硬件层面 4、虚拟地址空间布局 二、SMP/NUMA架构 三、伙伴系统及算法 1、基本伙伴分配器 2、分区伙伴分配器 四、块分配器(Slab/Slub/Slob) 1、基本概念 2、slab块分配器原理 …

【Linux运维】03-Linux文件管理

小伙伴们好&#xff0c;我是「 行走的程序喵」&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连~ &#x1f63b; 【Java基础】专栏&#xff0c;Java基础知识全面详解&#xff1a;&#x1f449;点击直达 &#x1f431; 【Mybatis框架】专栏&#xff0c;入门到基于XML的配置…

深入linux内核架构--slab分配器(建议收藏)

简介&#xff1a;malloc对于大家来说应该都不陌生了&#xff0c;这是系统库给我们提供了申请指定大小内存的函数&#xff0c;之前介绍的伙伴系统&#xff0c;只能以页的方式申请内存&#xff0c;对于小块(小于一页)内存的申请我们就得通过自定义的库函数来实现相关需求&#xf…

Linux内核进程与线程

Linux内核进程与线程 欢迎点击链接访问我的博客&#xff0c;了解更多内容&#xff01; 基本概念 进程就是处于执行期的程序(目标码存放在某种存储介质上)。但进程并不仅仅局限于一段可执行程序代码(Unix称其为代码段&#xff0c;text section)&#xff0c;通常进程还要包含其…

简述linux的slab分配器作用和原理,Linux中的slab分配器是什么?

Linux最近几年的发展迅速&#xff0c;很多中小企业网站都安装了Linux操作系统。本文将着重介绍Linux内核的内存管理&#xff0c;尤其是slab分配提供的机制。将探索slab分配器背后所采用的思想&#xff0c;并介绍这种方法提供的接口和用法。 slab 缓存 Linux所使用的slab分配器的…

剖析linux的内存管理与分配

文章目录 伙伴算法**1、伙伴算法原理****2、物理页的分配****3、 物理页的释放 ****总结** Slab分配机制**1、Slab如何对内存进行管理&#xff1f;****2、Slab中如何实现对页进行更细的划分&#xff1f;****3、Slab如何对内存进行分配**&#xff14;、Slab如何对数据结构slab进…

详细讲解Linux内核中伙伴系统和slab机制

伙伴系统 Linux内核中采用了一种同时适用于32位和64位系统的内存分页模型&#xff0c;对于32位系统来说&#xff0c;两级页表足够用了&#xff0c;而在x86_64系统中&#xff0c;用到了四级页表。四级页表分别为&#xff1a; 页全局目录(Page Global Directory) 页上级目录(P…

linux显卡用amd还是NVIDIA,Linux NVIDIA显卡驱动年度横评,不同于AMD,NVI

Linux NVIDIA显卡驱动年度横评,不同于AMD&#xff0c;NVI 年关将至&#xff0c;各种各样的总结越来越多&#xff0c;Phoronix就对2011年来的Linux NVIDIA显卡驱动进行了一次横向评测&#xff0c;一共收录了九个版本&#xff0c;横跨260-290多个系列。 不同于AMD&#xff0c;NVI…