diff --git a/_posts/linux/linux工具系列/02/浅谈linux内存管理.md b/_posts/linux/linux工具系列/02/浅谈linux内存管理.md index 4c7c6d0..28b8017 100644 --- a/_posts/linux/linux工具系列/02/浅谈linux内存管理.md +++ b/_posts/linux/linux工具系列/02/浅谈linux内存管理.md @@ -124,7 +124,7 @@ ![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy83ODQyNDY0LTc0N2U1ZmYxNzQ1NDhlNjAucG5n?x-oss-process=image/format,png) -所以,内核空间拿出了最后的 128M 地址区间,划分成下面三个高端内存映射区,以达到对整个物理地址范围的寻址。而在 64 位的系统上就不存在这样的问题了,因为可用的线性地址空间远大于可安装的内存。 +所以,内核空间拿出了最后的 128M 地址区间,划分成下面三个高端内存映射区,以达到对整个物理地址范围的寻址。而 在 64 位的系统上就不存在这样的问题了,因为可用的线性地址空间远大于可安装的内存。 ##### 动态内存映射区 @@ -191,7 +191,7 @@ **原创不易,看到这里,如果在我这有一点点收获,就动动手指「转发」和「在看」是对我持续创作的最大支持。** - + ## Reference diff --git a/_posts/linux/linux工具系列/03/kmalloc_vmalloc图解.png b/_posts/linux/linux工具系列/03/kmalloc_vmalloc图解.png new file mode 100644 index 0000000..2de25b8 Binary files /dev/null and b/_posts/linux/linux工具系列/03/kmalloc_vmalloc图解.png differ diff --git a/_posts/linux/linux工具系列/03/kmem_list3.png b/_posts/linux/linux工具系列/03/kmem_list3.png new file mode 100644 index 0000000..509d43e Binary files /dev/null and b/_posts/linux/linux工具系列/03/kmem_list3.png differ diff --git a/_posts/linux/linux工具系列/03/linux物理页管理算法.md b/_posts/linux/linux工具系列/03/linux物理页管理算法.md index ea845d7..e4dfe33 100644 --- a/_posts/linux/linux工具系列/03/linux物理页管理算法.md +++ b/_posts/linux/linux工具系列/03/linux物理页管理算法.md @@ -1,36 +1,63 @@ -上一篇文章我们分析了 Linux 内存管理机制, +今天继续来学习Linux内存管理,什么?你更想学时间管理,我不配,抱个西瓜去微博学吧。 -## 物理页管理 + ![img](https://i0.hdslb.com/bfs/article/666d2ea83d750ee420d79b3308f6cb164b9fc5a9.gif) -在`Linux `系统中通过分页机制把物理内存划分4K大小的内存页 `Page`(也称作页框`Page Frame`),物理内存的分配和回收都是基于内存页进行,假如系统请求小块内存,可以预先分配一页给他,避免了反复的申请和释放小块内存带来频繁的系统开销。假如系统需要大块内存,则可以用多页内存拼凑,而不必要求大块连续内存。 +言归正传,上一篇文章 [别再说你不懂Linux内存管理了,10张图给你安排的明明白白!](https://mp.weixin.qq.com/s?__biz=MzIwMjM4NDE1Nw==&mid=2247483865&idx=1&sn=dfa63a467b620b6131acaef9ea6874a3&chksm=96de37aba1a9bebdcc097314f40ae633bd393253759ecd970ac84cdb41f18994da9405dbf356&token=1178579599&lang=zh_CN#rd) 分析了 Linux 内存管理机制,如果已经忘了的同学还可以回头看下,并且也强烈建议先阅读那一篇再来看这一篇。限于篇幅,上一篇没有深入学习物理内存管理和虚拟内存分配,今天就来学习一下。 -我们知道无论内核还是进程,当实际需要访问内存的时候,如果虚拟内存没有映射到物理内存,会发生缺页中断,这时候会请求分配物理内存页框。 +通过前面的学习我们知道,程序可没这么好骗,任你内存管理把虚拟地址空间玩出花来,到最后还是要给程序实实在在的物理内存,不然程序就要罢工了,所以物理内存这么重要的资源一定要好好管理起来使用(物理内存,就是你实实在在的内存条),那么内核是如何管理物理内存的呢? + +## 物理内存管理 + +在`Linux `系统中通过分段和分页机制,把物理内存划分 4K 大小的内存页 `Page`(也称作页框`Page Frame`),物理内存的分配和回收都是基于内存页进行,把物理内存分页管理的好处大大的。 + +假如系统请求小块内存,可以预先分配一页给它,避免了反复的申请和释放小块内存带来频繁的系统开销。 + +假如系统需要大块内存,则可以用多页内存拼凑,而不必要求大块连续内存。你看不管内存大小都能收放自如,分页机制多么完美的解决方案! + + ![](https://i04piccdn.sogoucdn.com/615d4aeb28926430) + +But,理想很丰满,现实很骨感。如果就直接这样把内存分页使用,不再加额外的管理还是存在一些问题,下面我们来看下,系统在多次分配和释放物理页的时候会遇到哪些问题。 ### 物理页管理面临问题 -物理内存页分配会出现外部碎片和内部碎片问题,所谓的「内部」和「外部」是针对页框内外而言,页框内的内存碎片是内部碎片,页框间的碎片是外部碎片。 +物理内存页分配会出现外部碎片和内部碎片问题,所谓的「内部」和「外部」是针对「页框内外」而言,一个页框内的内存碎片是内部碎片,多个页框间的碎片是外部碎片。 #### 外部碎片 -分配物理内存页的时候会尽量分配连续的内存页面,频繁的分配与回收物理页导致大量的小块内存夹杂在已分配页面中间,形成外部碎片。举个例子: +当需要分配大块内存的时候,要用好几页组合起来才够,而系统分配物理内存页的时候会尽量分配连续的内存页面,频繁的分配与回收物理页导致大量的小块内存夹杂在已分配页面中间,形成外部碎片,举个例子: +![外部碎片](https://upload-images.jianshu.io/upload_images/7842464-39b54d3f1acf2f86.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) #### 内部碎片 -以页为单位管理和分配内存,这就导致每次分配的都至少是4K大小的页面,而内核中有很多需要以字节为单位分配内存的场景,这样本来只想要几个字节而已却不得不分配一页内存,除去用掉的字节剩下的就形成了内部碎片。 +物理内存是按页来分配的,这样当实际只需要很小内存的时候,也会分配至少是 4K 大小的页面,而内核中有很多需要以字节为单位分配内存的场景,这样本来只想要几个字节而已却不得不分配一页内存,除去用掉的字节剩下的就形成了内部碎片。 +![内部碎片](https://upload-images.jianshu.io/upload_images/7842464-496b0cfd4d779633.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### 页面管理算法 +方法总比困难多,因为存在上面的这些问题,聪明的程序员灵机一动,引入了页面管理算法来解决上述的碎片问题。 + #### Buddy(伙伴)分配算法 - Linux内核中引入了伙伴系统算法(Buddy system)。把所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。因为任何正整数都可以由2^n的和组成,所以总能找到合适大小的内存块分配出去,减少了外部碎片产生 。 + `Linux` 内核引入了伙伴系统算法(Buddy system),什么意思呢?就是把相同大小的页框块用链表串起来,页框块就像手拉手的好伙伴,也是这个算法名字的由来。 -比如:我需要申请4个页框,但是长度为4个连续页框块链表没有空闲的页框块,伙伴系统会从连续8个页框块的链表获取一个,并将其拆分为两个连续4个页框块,放入连续4个页框块的链表中。释放的时候也一样,会检查释放的这几个页框的之前和之后的物理页框是否空闲,并且能否组成下一级长度的块。 + ![](https://i04piccdn.sogoucdn.com/3182f7a569acc1c1) -#### 命令查看 +具体的,所有的空闲页框分组为11个块链表,每个块链表分别包含大小为1,2,4,8,16,32,64,128,256,512和1024个连续页框的页框块。最大可以申请1024个连续页框,对应4MB大小的连续内存。 + +![伙伴系统](https://upload-images.jianshu.io/upload_images/7842464-25a3e9bd900cb55c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +因为任何正整数都可以由 `2^n` 的和组成,所以总能找到合适大小的内存块分配出去,减少了外部碎片产生 。 + +##### 分配实例 + +比如:我需要申请4个页框,但是长度为4个连续页框块链表没有空闲的页框块,伙伴系统会从连续8个页框块的链表获取一个,并将其拆分为两个连续4个页框块,取其中一个,另外一个放入连续4个页框块的空闲链表中。释放的时候会检查,释放的这几个页框前后的页框是否空闲,能否组成下一级长度的块。 + +##### 命令查看 ``` [lemon]]# cat /proc/buddyinfo @@ -44,77 +71,178 @@ Node 0, zone Normal 42438 37404 16035 4386 610 121 22 3 #### slab分配器 -伙伴系统分配出去的内存还是以页框为单位,对于内核的很多场景来说还是太大,于是就有了` slab `分配器。 +看到这里你可能会想,有了伙伴系统这下总可以管理好物理内存了吧?不,还不够,否则就没有slab分配器什么事了。 -Slab是一种内存分配器,通过将内存划分不同大小的空间分配给对象使用来进行缓存管理,应用于内核对象的缓存。 + ![](https://i02piccdn.sogoucdn.com/980b9721e70eedae) -slab分配器是基于对象进行管理的,所谓的对象就是内核中的数据结构(例如:`task_struct、file_struct` 等)。相同类型的对象归为一类,每当要申请这样一个对象时,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免内部碎片。slab分配器并不丢弃已经分配的对象,而是释放并把它们保存在内存中。slab分配对象时,会使用最近释放的对象的内存块,因此其驻留在cpu高速缓存中的概率会大大提高。 +那什么是slab分配器呢? -- Slab对小对象进行分配,不用为每个小对象分配一个页,节省了空间。 -- 内核中一些小对象创建析构很频繁,Slab对这些小对象做缓存,可以重复利用一些相同的对象,减少内存分配次数。 +一般来说,内核对象的生命周期是这样的:分配内存-初始化-释放内存,内核中有大量的小对象,比如文件描述结构对象、任务描述结构对象,如果按照伙伴系统按页分配和释放内存,对小对象频繁的执行「分配内存-初始化-释放内存」会非常消耗性能。 -![image-20200421202943561](C:\Users\linlongchen\AppData\Roaming\Typora\typora-user-images\image-20200421202943561.png) +伙伴系统分配出去的内存还是以页框为单位,而对于内核的很多场景都是分配小片内存,远用不到一页内存大小的空间。` slab `分配器,**通过将内存按使用对象不同再划分成不同大小的空间**,应用于内核对象的缓存。 -kmem_cache是一个cache_chain的链表,描述了一个高速缓存,每个高速缓存包含了一个slabs的列表,这通常是一段连续的内存块。存在3种slab: +伙伴系统和slab不是二选一的关系,`slab` 内存分配器是对伙伴分配算法的补充。 -- slabs_full(完全分配的slab) -- slabs_partial(部分分配的slab) -- slabs_empty(空slab,或者没有对象被分配)。 +##### 大白话说原理 -slab是slab分配器的最小单位,在实现上一个slab有一个货多个连续的物理页组成(通常只有一页)。单个slab可以在slab链表之间移动,例如如果一个半满slab被分配了对象后变满了,就要从slabs_partial中被删除,同时插入到slabs_full中去。 +对于每个内核中的相同类型的对象,如:`task_struct、file_struct` 等需要重复使用的小型内核数据对象,都会有个 slab 缓存池,缓存住大量常用的「已经初始化」的对象,每当要申请这种类型的对象时,就从缓存池的`slab` 列表中分配一个出去;而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免内部碎片,同时也大大提高了内存分配性能。 + +##### 主要优点 + +- `slab` 内存管理基于内核小对象,不用每次都分配一页内存,充分利用内存空间,避免内部碎片。 +- `slab` 对内核中频繁创建和释放的小对象做缓存,重复利用一些相同的对象,减少内存分配次数。 + +##### 数据结构 + +![slab分配器](https://upload-images.jianshu.io/upload_images/7842464-d3d1a3ed84ac2960.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +`kmem_cache` 是一个`cache_chain` 的链表组成节点,代表的是一个内核中的相同类型的「对象高速缓存」,每个`kmem_cache` 通常是一段连续的内存块,包含了三种类型的 `slabs` 链表: + +- `slabs_full` (完全分配的 `slab` 链表) +- ` slabs_partial` (部分分配的`slab` 链表) +- `slabs_empty` ( 没有被分配对象的`slab` 链表) + +`kmem_cache` 中有个重要的结构体 `kmem_list3` 包含了以上三个数据结构的声明。 + +![kmem_list3 内核源码](https://upload-images.jianshu.io/upload_images/7842464-ff27149b346c7f1b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +`slab` 是` slab` 分配器的最小单位,在实现上一个 `slab` 有一个或多个连续的物理页组成(通常只有一页)。单个slab可以在 `slab` 链表之间移动,例如如果一个「半满` slabs_partial`链表」被分配了对象后变满了,就要从 `slabs_partial` 中删除,同时插入到「全满`slabs_full`链表」中去。内核` slab `对象的分配过程是这样的: + +1. 如果` slabs_partial`链表还有未分配的空间,分配对象,若分配之后变满,移动 `slab` 到`slabs_full` 链表 +2. 如果` slabs_partial`链表没有未分配的空间,进入下一步 +3. 如果`slabs_empty` 链表还有未分配的空间,分配对象,同时移动` slab `进入` slabs_partial`链表 +4. 如果`slabs_empty`为空,请求伙伴系统分页,创建一个新的空闲`slab`, 按步骤 3 分配对象 + +![slab分配图解](https://upload-images.jianshu.io/upload_images/7842464-e830d87e9bd2cba0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -#### 命令查看 -`cat /proc/slabinfo` +##### 命令查看 -![image-20200421203357847](C:\Users\linlongchen\AppData\Roaming\Typora\typora-user-images\image-20200421203357847.png) +上面说的都是理论,比较抽象,动动手来康康系统中的 slab 吧!你可以通过 `cat /proc/slabinfo` 命令,实际查看系统中` slab` 信息。 - `kmalloc() ` 也是基于 SLAB 分配器的,只不过它所需要的管理结构头已经按照 2^n 的大小排列事先准备好了 +![slabinfo查询](https://upload-images.jianshu.io/upload_images/7842464-1a310d5b729d0a25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -可以看到slabinfo的信息有` kmalloc `相关 `slab `对象信息 -![image-20200421204315596](C:\Users\linlongchen\AppData\Roaming\Typora\typora-user-images\image-20200421204315596.png) +`slabtop` 实时显示内核 slab 内存缓存信息。 -`slabtop` - -![image-20200421203542312](C:\Users\linlongchen\AppData\Roaming\Typora\typora-user-images\image-20200421203542312.png) +![slabtop查询](https://upload-images.jianshu.io/upload_images/7842464-69926181eda4d902.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) -## 三个内存分配函数 -### 用户空间malloc +#### slab高速缓存的分类 -当申请小于 128KB 小内存的时,` malloc `使用 `sbrk` 分配内存;当申请大于 128KB 的内存时,使用 `mmap` 函数申请内存;但是这只是分配了虚拟内存,还没有映射到物理内存,当访问申请的内存时,才会因为缺页异常,内核分配物理内存。 +slab高速缓存分为两大类,「通用高速缓存」和「专用高速缓存」。 - 由于brk/sbrk/mmap属于系统调用,如果每次申请内存,都调用这三个函数中的一个,那么每次都要产生系统调用开销(即cpu从用户态切换到内核态的上下文切换,这里要保存用户态数据,等会还要切换回用户态),这是非常影响性能的;其次,这样申请的内存容易产生碎片,因为堆是从低地址到高地址,如果低地址的内存没有被释放,高地址的内存就不能被回收。 +##### 通用高速缓存 -因此,` malloc `采用的是内存池的实现方式,malloc内存池实现方式更类似于 STL 分配器和 memcached 的内存池,先申请一大块内存,然后将内存分成不同大小的内存块,然后用户申请内存时,直接从内存池中选择一块相近的内存块即可。 +slab分配器中用 `kmem_cache` 来描述高速缓存的结构,它本身也需要 slab 分配器对其进行高速缓存。cache_cache 保存着对「高速缓存描述符的高速缓存」,是一种通用高速缓存,保存在`cache_chain` 链表中的第一个元素。 + + +另外,slab 分配器所提供的小块连续内存的分配,也是通用高速缓存实现的。通用高速缓存所提供的对象具有几何分布的大小,范围为32到131072字节。内核中提供了 `kmalloc()` 和 `kfree()` 两个接口分别进行内存的申请和释放。 + +##### 专用高速缓存 + +内核为专用高速缓存的申请和释放提供了一套完整的接口,根据所传入的参数为制定的对象分配slab缓存。 + +###### 专用高速缓存的申请和释放 + +kmem_cache_create() 用于对一个指定的对象创建高速缓存。它从 cache_cache 普通高速缓存中为新的专有缓存分配一个高速缓存描述符,并把这个描述符插入到高速缓存描述符形成的 cache_chain 链表中。kmem_cache_destory() 用于撤消和从 cache_chain 链表上删除高速缓存。 + +##### slab的申请和释放 + +`slab` 数据结构在内核中的定义,如下: + +![slab结构体内核代码](https://upload-images.jianshu.io/upload_images/7842464-8f1e770cb728e37e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +kmem_cache_alloc() 在其参数所指定的高速缓存中分配一个slab,对应的 kmem_cache_free() 在其参数所指定的高速缓存中释放一个slab。 -### 内核空间kmalloc +## 虚拟内存分配 -这个函数用于分配内核空间的虚拟内存 +前面讨论的都是对物理内存的管理,Linux 通过虚拟内存管理,欺骗了用户程序假装每个程序都有 4G 的虚拟内存寻址空间(如果这里不懂我说啥,建议回头看下 [别再说你不懂Linux内存管理了,10张图给你安排的明明白白!](https://mp.weixin.qq.com/s?__biz=MzIwMjM4NDE1Nw==&mid=2247483865&idx=1&sn=dfa63a467b620b6131acaef9ea6874a3&chksm=96de37aba1a9bebdcc097314f40ae633bd393253759ecd970ac84cdb41f18994da9405dbf356&token=1178579599&lang=zh_CN#rd))。 -`kmalloc` 按字节为单位虚拟内存,一般用于分配小块内存,释放内存对应于 `kfree` ,可以分配连续的物理内存。函数原型在 `` 中声明。 kmalloc 分配内存是基于slab,因此slab的一些特性包括着色,对齐等都具备,性能较好,一般情况下在驱动程序中都是调用kmalloc()来给数据结构分配内存 。 +所以我们来研究下虚拟内存的分配,这里包括用户空间虚拟内存和内核空间虚拟内存。 - kmalloc()分配的内存处于3GB~high_memory之间的直接内存映射区。 +**注意,分配的虚拟内存还没有映射到物理内存,只有当访问申请的虚拟内存时,才会发生缺页异常,再通过上面介绍的伙伴系统和 slab 分配器申请物理内存。** -### 内核空间vmalloc +### 用户空间内存分配 -`vmalloc` 按字节为单位虚拟内存,一般用分配大块内存,释放内存对应于 `vfree`,分配连续的虚拟内存,但是物理上不一定连续。函数原型在 `` 中声明。 一般用在为活动的交换区分配数据结构,为某些I/O驱动程序分配缓冲区,或为模块分配空间。 +#### malloc -vmalloc()分配的内存在VMALLOC_START~4GB之间,也就是非连续的动态内存映射区。 +`malloc` 用于申请用户空间的虚拟内存,当申请小于 `128KB` 小内存的时,` malloc `使用 `sbrk或brk` 分配内存;当申请大于 `128KB` 的内存时,使用 `mmap` 函数申请内存; + +##### 存在问题 + +由于 `brk/sbrk/mmap` 属于系统调用,如果每次申请内存都要产生系统调用开销,`cpu` 在用户态和内核态之间频繁切换,非常影响性能。 + +而且,堆是从低地址往高地址增长,如果低地址的内存没有被释放,高地址的内存就不能被回收,容易产生内存碎片。 + +##### 解决 + +因此,` malloc `采用的是内存池的实现方式,先申请一大块内存,然后将内存分成不同大小的内存块,然后用户申请内存时,直接从内存池中选择一块相近的内存块分配出去。 +![malloc原理](https://upload-images.jianshu.io/upload_images/7842464-26e7d450551a4631.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + +### 内核空间内存分配 + +在讲内核空间内存分配之前,先来回顾一下内核地址空间。`kmalloc` 和 `vmalloc` 分别用于分配不同映射区的虚拟内存。 + +![内核空间细分区域.](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy83ODQyNDY0LWZmZTNlNGQ4ZDc5ZjNmNGMucG5n?x-oss-process=image/format,png) + +#### kmalloc + +`kmalloc()` 分配的虚拟地址范围在内核空间的「直接内存映射区」。 + +按字节为单位虚拟内存,一般用于分配小块内存,释放内存对应于 `kfree` ,可以分配连续的物理内存。函数原型在 `` 中声明,一般情况下在驱动程序中都是调用 `kmalloc()` 来给数据结构分配内存 。 + +还记得前面说的 slab 吗?`kmalloc` 是基于slab 分配器的 ,同样可以用`cat /proc/slabinfo` 命令,查看 `kmalloc` 相关 `slab` 对象信息,下面的 kmalloc-8、kmalloc-16 等等就是基于slab分配的 kmalloc 高速缓存。 + +![slabinfo-kmalloc](https://upload-images.jianshu.io/upload_images/7842464-159cafcb9fca21cd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + +#### vmalloc + +`vmalloc` 分配的虚拟地址区间,位于 `vmalloc_start` 与 ` vmalloc_end` 之间的「动态内存映射区」。 + +一般用分配大块内存,释放内存对应于 `vfree`,分配的虚拟内存地址连续,物理地址上不一定连续。函数原型在 `` 中声明。一般用在为活动的交换区分配数据结构,为某些 `I/O` 驱动程序分配缓冲区,或为内核模块分配空间。 + +下面的图总结了上述两种内核空间虚拟内存分配方式。 +![kmalloc_vmalloc图解](https://upload-images.jianshu.io/upload_images/7842464-0479ee1ebb47e96f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) + + + + +## 总结一下 + +这是`Linux `内存管理系列文章的下篇,强烈建议阅读过程中有不清楚的同学,先去看看我之前写的 [别再说你不懂Linux内存管理了,10张图给你安排的明明白白!](https://mp.weixin.qq.com/s?__biz=MzIwMjM4NDE1Nw==&mid=2247483865&idx=1&sn=dfa63a467b620b6131acaef9ea6874a3&chksm=96de37aba1a9bebdcc097314f40ae633bd393253759ecd970ac84cdb41f18994da9405dbf356&token=1178579599&lang=zh_CN#rd),写到这里Linux 内存管理专题告一段落,我分享的这些知识很基础,基础到日常开发工作几乎用不上,但我认为每个在Linux下开发人员都应该了解。 + +我知道有些面试官喜欢在面试的时候考察一下,或多或少反应候选人基础素养,这两篇文章的内容也足够应付面试。还是那句话,Linxu 内存管理太复杂,不是一两篇文章能讲的清楚,但至少要有宏观意识,不至于一问三不知,如果你想深入了解原理,强烈建议从书中并结合内核源码学习,每天进步一点点,我们的目标是星辰大海。 + +**本文创作过程我也画了大量的示例图解,可以作为知识索引,个人感觉看图还是比看文字更清晰明了,你可以在我公众号「后端技术学堂」后台回复「内存管理」获取这些图片的高清原图。** + +老规矩,感谢各位的阅读,文章的目的是分享对知识的理解,技术类文章我都会反复求证以求最大程度保证准确性,若文中出现明显纰漏也欢迎指出,我们一起在探讨中学习。今天的技术分享就到这里,我们下期再见。 + +**原创不易,看到这里,如果在我这有一点点收获,就动动手指「转发」和「在看」是对我持续创作的最大支持。** ## Reference +《Linux内核设计与实现(原书第3版)》 + linux内核slab机制分析 https://www.jianshu.com/p/95d68389fbd1 + Linux内存管理中的slab分配器 http://edsionte.com/techblog/archives/4019 + Linux slab 分配器剖析 https://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/index.html#table2 Linux内核内存管理算法Buddy和Slab https://zhuanlan.zhihu.com/p/36140017 @@ -127,8 +255,6 @@ malloc实现原理 http://luodw.cc/2016/02/17/malloc/ glibc内存管理那些事儿 https://www.jianshu.com/p/2fedeacfa797 -Kmalloc和Vmalloc的区别 https://www.cnblogs.com/wuchanming/p/4465155.html - - + \ No newline at end of file diff --git a/_posts/linux/linux工具系列/03/malloc原理.png b/_posts/linux/linux工具系列/03/malloc原理.png new file mode 100644 index 0000000..3f33059 Binary files /dev/null and b/_posts/linux/linux工具系列/03/malloc原理.png differ diff --git a/_posts/linux/linux工具系列/03/slabinfo-kmalloc.png b/_posts/linux/linux工具系列/03/slabinfo-kmalloc.png new file mode 100644 index 0000000..4246362 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slabinfo-kmalloc.png differ diff --git a/_posts/linux/linux工具系列/03/slabinfo.png b/_posts/linux/linux工具系列/03/slabinfo.png new file mode 100644 index 0000000..980d9c4 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slabinfo.png differ diff --git a/_posts/linux/linux工具系列/03/slabtop.png b/_posts/linux/linux工具系列/03/slabtop.png new file mode 100644 index 0000000..f09aa89 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slabtop.png differ diff --git a/_posts/linux/linux工具系列/03/slab分配器.png b/_posts/linux/linux工具系列/03/slab分配器.png new file mode 100644 index 0000000..582ee78 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slab分配器.png differ diff --git a/_posts/linux/linux工具系列/03/slab分配图解.png b/_posts/linux/linux工具系列/03/slab分配图解.png new file mode 100644 index 0000000..eb0c797 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slab分配图解.png differ diff --git a/_posts/linux/linux工具系列/03/slab结构.png b/_posts/linux/linux工具系列/03/slab结构.png new file mode 100644 index 0000000..a391672 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slab结构.png differ diff --git a/_posts/linux/linux工具系列/03/slab结构体.png b/_posts/linux/linux工具系列/03/slab结构体.png new file mode 100644 index 0000000..84191d3 Binary files /dev/null and b/_posts/linux/linux工具系列/03/slab结构体.png differ diff --git a/_posts/linux/linux工具系列/03/伙伴系统.png b/_posts/linux/linux工具系列/03/伙伴系统.png new file mode 100644 index 0000000..cadb39e Binary files /dev/null and b/_posts/linux/linux工具系列/03/伙伴系统.png differ diff --git a/_posts/linux/linux工具系列/03/内存管理slab.drawio b/_posts/linux/linux工具系列/03/内存管理slab.drawio new file mode 100644 index 0000000..22c1c49 --- /dev/null +++ b/_posts/linux/linux工具系列/03/内存管理slab.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/_posts/linux/linux工具系列/03/内部碎片.png b/_posts/linux/linux工具系列/03/内部碎片.png new file mode 100644 index 0000000..87be819 Binary files /dev/null and b/_posts/linux/linux工具系列/03/内部碎片.png differ diff --git a/_posts/linux/linux工具系列/03/外部碎片.png b/_posts/linux/linux工具系列/03/外部碎片.png new file mode 100644 index 0000000..7b2d0f2 Binary files /dev/null and b/_posts/linux/linux工具系列/03/外部碎片.png differ