打印
[其他ST产品]

一文搞定Linux内存管理原理(转)

[复制链接]
楼主: shjuturt
手机看帖
扫描二维码
随时随地手机跟帖
21
shjuturt|  楼主 | 2022-7-28 16:56 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
11、我们进入另外一个级别,order(3)。它的位索引为0,它的值同样为0。这意味着对应的伙伴不是全部空闲的,所以没有再进一步合并的可能。我们仅设置该bit为1,然后将合并得到的空闲页面块放入order(3)空闲链表中。


12、最终我们得到大小为8个页面的空闲块,

使用特权

评论回复
22
shjuturt|  楼主 | 2022-7-28 17:06 | 只看该作者

使用特权

评论回复
23
shjuturt|  楼主 | 2022-7-28 17:10 | 只看该作者
buddy避免内部碎片的努力


物理内存的碎片化一直是Linux操作系统的弱点之一,尽管已经有人提出了很多解决方法,但是没有哪个方法能够彻底的解决,memory buddy分配就是解决方法之一。 我们知道磁盘文件也有碎片化问题,但是磁盘文件的碎片化只会减慢系统的读写速度,并不会导致功能性错误,而且我们还可以在不影响磁盘功能的前提的下,进行磁盘碎片整理。而物理内存碎片则截然不同,物理内存和操作系统结合的太过于紧密,以至于我们很难在运行时,进行物理内存的搬移(这一点上,磁盘碎片要容易的多;实际上mel gorman已经提交了内存紧缩的patch,只是还没有被主线内核接收)。 因此解决的方向主要放在预防碎片上。在2.6.24内核开发期间,防止碎片的内核功能加入了主线内核。

使用特权

评论回复
24
shjuturt|  楼主 | 2022-7-28 17:10 | 只看该作者
在了解反碎片的基本原理前,先对内存页面做个归类:


不可移动页面 unmoveable:在内存中位置必须固定,无法移动到其他地方,核心内核分配的大部分页面都属于这一类。

使用特权

评论回复
25
shjuturt|  楼主 | 2022-7-28 17:13 | 只看该作者
可回收页面 reclaimable:不能直接移动,但是可以回收,因为还可以从某些源重建页面,比如映射文件的数据属于这种类别,kswapd会按照一定的规则,周期性的回收这类页面。

使用特权

评论回复
26
shjuturt|  楼主 | 2022-7-28 17:13 | 只看该作者
可移动页面 movable:可以随意的移动。属于用户空间应用程序的页属于此类页面,它们是通过页表映射的,因此我们只需要更新页表项,并把数据复制到新位置就可以了,当然要注意,一个页面可能被多个进程共享,对应着多个页表项。

使用特权

评论回复
27
shjuturt|  楼主 | 2022-7-28 17:34 | 只看该作者
防止碎片的方法就是把这三类page放在不同的链表上,避免不同类型页面相互干扰。考虑这样的情形,一个不可移动的页面位于可移动页面中间,那么我们移动或者回收这些页面后,这个不可移动的页面阻碍着我们获得更大的连续物理空闲空间。

使用特权

评论回复
28
shjuturt|  楼主 | 2022-7-28 17:35 | 只看该作者
每个zone区都有一个自己的失活净页面队列,与此对应的是两个跨zone的全局队列,失活脏页队列 和 活跃队列。这些队列都是通过page结构的lru指针链入的。

使用特权

评论回复
29
shjuturt|  楼主 | 2022-7-28 17:37 | 只看该作者
思考:失活队列的意义是什么(见)?内核源代码情景分析>


slab分配器:解决内部碎片问题

使用特权

评论回复
30
shjuturt|  楼主 | 2022-7-28 17:39 | 只看该作者
内核通常依赖于对小对象的分配,它们会在系统生命周期内进行无数次分配。slab 缓存分配器通过对类似大小(远小于1page)的对象进行缓存而提供这种功能,从而避免了常见的内部碎片问题。此处暂贴一图,关于其原理,常见参考文献3。很显然,slab机制是基于buddy算法的,前者是对后者的细化

使用特权

评论回复
31
shjuturt|  楼主 | 2022-7-28 17:42 | 只看该作者

使用特权

评论回复
32
shjuturt|  楼主 | 2022-7-28 17:59 | 只看该作者
页面回收/侧重机制


页面回收简述


有页面分配,就会有页面回收。页面回收的方法大体上可分为两种:

使用特权

评论回复
33
shjuturt|  楼主 | 2022-7-28 18:00 | 只看该作者
一是主动释放。就像用户程序通过free函数释放曾经通过malloc函数分配的内存一样,页面的使用者明确知道页面什么时候要被使用,什么时候又不再需要了。 上面提到的前两种分配方式,一般都是由内核程序主动释放的。对于直接从伙伴系统分配的页面,这是由使用者使用free_pages之类的函数主动释放的,页面释放后被直接放归伙伴系统;从slab中分配的对象(使用kmem_cache_alloc函数),也是由使用者主动释放的(使用kmem_cache_free函数)。

使用特权

评论回复
34
shjuturt|  楼主 | 2022-7-28 18:04 | 只看该作者
另一种页面回收方式是通过linux内核提供的页框回收算法(PFRA)进行回收。页面的使用者一般将页面当作某种缓存,以提高系统的运行效率。缓存一直存在固然好,但是如果缓存没有了也不会造成什么错误,仅仅是效率受影响而已。页面的使用者不明确知道这些缓存页面什么时候最好被保留,什么时候最好被回收,这些都交由PFRA来关心。

使用特权

评论回复
35
shjuturt|  楼主 | 2022-7-28 18:06 | 只看该作者
简单来说,PFRA要做的事就是回收这些可以被回收的页面。为了避免系统陷入页面紧缺的困境,PFRA会在内核线程中周期性地被调用运行。或者由于系统已经页面紧缺,试图分配页面的内核执行流程因为得不到需要的页面,而同步地调用PFRA。

使用特权

评论回复
36
shjuturt|  楼主 | 2022-7-28 18:07 | 只看该作者
上面提到的后两种分配方式,一般是由PFRA来进行回收的(或者由类似删除文件、进程退出、这样的过程来同步回收)。


PFRA回收一般页面

使用特权

评论回复
37
shjuturt|  楼主 | 2022-7-28 18:08 | 只看该作者
而对于上面提到的前两种页面分配方式(直接分配页面和通过slab分配对象),也有可能需要通过PFRA来回收。


页面的使用者可以向PFRA注册回调函数(使用register_shrink函数)。然后由PFRA在适当的时机来调用这些回调函数,以触发对相应页面或对象的回收。

使用特权

评论回复
38
shjuturt|  楼主 | 2022-7-28 18:09 | 只看该作者
其中较为典型的是对dentry的回收。dentry是由slab分配的,用于表示虚拟文件系统目录结构的对象。在dentry的引用记数被减为0的时候,dentry并不是直接被释放,而是被放到一个LRU链表中缓存起来,便于后续的使用。

使用特权

评论回复
39
shjuturt|  楼主 | 2022-7-28 18:10 | 只看该作者
而这个LRU链表中的dentry最终是需要被回收的,于是虚拟文件系统在初始化时,调用register_shrinker注册了回收函数shrink_dcache_memory。

使用特权

评论回复
40
稳稳の幸福| | 2022-7-29 11:24 | 只看该作者
学习学习

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则