[文章]

鸿蒙内核源码分析(内存概念篇) :手眼通天的虚拟内存

2020-11-20 13:52:32  328 鸿蒙系统 内核 内存
分享
2
最难讲的章节
        内存模块占了 HarmonyOS 内核约15%代码量, 近20个.c文件,很复杂。系列篇将用九篇来介绍HarmonyOS内存部分,分别是 鸿蒙内核源码分析(内存概念篇) | 鸿蒙内核源码分析(内存管理篇) | 鸿蒙内核源码分析(内存汇编篇) |  鸿蒙内核源码分析(内存分配篇)  |  鸿蒙内核源码分析(内存映射篇)  | 鸿蒙内核源码分析(内存空间篇)  | 鸿蒙内核源码分析(内存置换篇)  | 鸿蒙内核源码分析(内存共享篇) | 鸿蒙内核源码分析(内存故事篇) 故事篇中会用生活场景张大爷故事里的另一个主角王场馆来举例 ,这些篇幅内容也会反复修改完善。想想也是内存何等重要,内核本身也是程序要运行空间, 用户程序也要在运行空间,大家都在一个窝里吃饭, 你凭什么就管我了, 凭什么的问题会在系列篇的最后结尾 鸿蒙内核源码分析(主奴机制篇) 中详细介绍, 哎! 其实用户进程就是内核的一个个奴才, 被捏的死死的.  按不住奴才那这主子就不合格,就不是一个稳定的运作系统. 试着想想 实际内存就这么点大, 如何满足众多用户进程的需求? 内核空间和用户空间如何隔离? 如何防止访问乱串? 如何分配如何释放防止碎片化? 空间不够了又如何置换到硬盘?   想想头都大了。内核这当家的主子真是不容易,这些都是他要解决的问题, 欲戴其冠,必承其重嘛.本章是笔者认真读完鸿蒙内存模块代码后的总结,获益良多,讲之前先重新梳理下内存的一些概念再来详细阐述内存模块的其他细节. 那开始吧。

先说如果没有内存管理会怎样?
       那就是个奴才们能把主子给活活踩死, 想想主奴不分,吃喝拉撒睡都在一起,称兄道弟的想干啥? 没规矩不成方圆嘛,这事业肯定搞不大,单片机时代就是这种情况. 裸机编程,指针可以随便乱飞,数据可以随意覆盖,没有划定边界,没有明确职责,没有特权指令,没有地址保护,你还想像java开发一样,只管new内存,不去释放,应用可以随便崩但系统跑的妥妥的?想的美! 直接系统死机,甚至开机都开不了,主板直接报废了. 所以不能运行很复杂的程序,尽量可控,而且更是不可能支持应用的动态加载运行. 队伍大了就不好带了,方法得换, 游击队的做法不适合规模作战,内存就需要管理了,而且是 5A级的严格管理。

内存管理在管什么?
        简单说就是给主子赋能,拥有超级权利,为什么就他有? 因为他先来,掌握了先机.它定好了游戏规则,你们来玩.有哪些游戏规则?
        第一: 主奴有别,主子即是裁判又是运动员,主子有主子地方,奴才们有奴才们待的地方,主子可以在你的空间走来走去,但你只能在主人划定的区域活动.奴才把自己玩崩了也只是奴才狗屁了, 但主人和其他人还会是好好的. 主子有所有特权,比如某个奴才太嚣张了,就直接拖到午门问斩。
        第二: 奴奴有分,奴才们基本都是平等的,虽有高级和低级奴才区分,但本质都是奴才。奴才之间是不能随意勾连,登门问客的,防止一块搞政变. 他们都有属于自己的活动空间,而且活动空间还巨大巨大,大到奴才们觉得整个紫荆城都是他们家的,给你这么大空间你干活才有动力,奴才们是铆足了劲一个个尽情的表演各种剧本,有玩电子商务的,有玩游戏的,有搞直播的等等。。。不愧是紫荆城的主人很有一套,明明只有一个紫禁城,硬被他整出了N个紫荆城的感觉。而且这套驾奴本领还取了个很好听的名字叫:虚拟内存。HarmonyOS关于内存部分的中文注解已基本完成,可前往代码仓库 鸿蒙内核源码注释中文版 【 Gitee仓 | CSDN仓 | Github仓 | Coding仓 】详细阅读。虚拟内存长啥样?鸿蒙虚拟内存全景图:

这是整个紫荆城的全貌图,里面的内核虚拟空间是主人专用的,里面放的是主人的资料,数据,奴才永远进不去,kernel heap 也是给主人专用的动态内存空间,管理奴才和日常运作开销很多时候需要动态申请内存,这个是专门用来提供给主人使用的。而所有奴才的空间都在叫用户空间的那一块。你没看错,是所有奴才的都在那。当然实际情况是用户空间比图中的大的多,因为主人其实用不了多少空间,大部分是留给奴才们干活用了,因为篇幅的限制笔者把用户空间压缩了下。 再来看看奴才空间是啥样的。看图


这张图是第一张图的局部用户空间放大图。里面放的是奴才的私人用品,数据,task运行栈区,动态分配内存的堆区,堆区自下而上,栈区自上而下中间有虚拟地址<--->物理地址的映射区隔开。这么多奴才在里面不挤吗?答案是:真不挤 。主人手眼通天,因为用了一个好帮手解决了这个问题,这个帮手名叫 MMU(李大总管)
MMU是干什么事的?
看下某度对MMU定义:它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件。它的功能包括虚拟地址到物理地址的转换(即虚拟内存管理)、内存保护、中央处理器高速缓存的控制。通过它的一番操作,把物理空间成倍成倍的放大,他们之间的映射关系存放在页面中。
好像看懂又好像没看懂是吧,到底是干啥的?其实就是个地址映射登记中心。记住这两个字:映射 看下图
物理内存可以理解为真实世界的紫禁城,虚拟内存就是被MMU虚拟出来的比物理页面大的多的空间。举例说明大概说明下过程:

有A,B,C 三个奴才来到紫禁城,每个人都很有抱负,主子规定要先跑去登记处登记活动范围,领回来一张表 叫 L1页表,上面说了大半个紫禁城你可以跑动,都是你的,L1页表记录你详细了每个房间的编号。其实奴才们的表都一样,能跑的范围也都一样。

怎么跑呢?在CPU单核的情况下同时只能有一个人在跑,CPU双核就是两个人跑,其他人都看着他们跑,等待主人叫到自己的号去跑。每个人跑之前先把领的表交给地址映射中心的负责人李大总管,比如A需要把自己编号999号房的菜拿出来切炒,李大总管拿表一看 999号对应的是 88号真实房间,而88号已经有B奴才的东西了,怎么办?简单啊,把B奴才的东西移到城外的仓库,再把A数据从城外移到88号房。这样A就拿到了他认为的是在999号房的菜,它全程都不用知道 88号房。记住这是映射的核心机制!!! 这个过程涉及到两个内存概念:缺页中断和页面置换。缺页中断就是88号房被B占了发出一个中断信号,页面置换就是把88号房的东西先搬到城外B的仓库,才从A仓库的菜搬到88号房。李大总管最后更新下内部表,88号仓给了A奴才用。李大总管的私人表叫 TLB(translation lookaside buffer)可翻译为“地址转换后援缓冲器”,也可简称为“快表”。简单地说,TLB就是页表的Cache

置换就要有算法,常用的是 LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。

虚拟内存和物理内存的管理分配方式是不一样的,但都是以页(page)为单位来管理,一页4K字节。

物理内存:段页管理,伙伴算法分配(buddy算法)。

LOS_PhysPagesAllocContiguous 这里只到函数级,物理内存的管理和分配很简单,知道伙伴算法的原理就搞清楚了物理内存的管理。啥是伙伴算法?简单说就是把蛋糕按 2^0,2^1...2^order先切成一块块的, 2^0的统一放一起,2^order的统一放一起,有几个order就用几个链表管理,颗粒粗,分配至少一页起。

虚拟内存:线性区管理,内存池分配(slab算法)。LOS_MemAlloc 内存池分配,细颗粒分配,从物理内存拿了一页空间,根据需要再割给申请方。

举例说下流程:A用户向虚拟内存申请 1K内存,虚拟内存一看内存池里只有半K(512)了,不够就向物理内存管理方要了一页(4K),再割1K给A。

虚拟内存管理在鸿蒙主要由 VmMapRegion 这个结构体来串联,很复杂,什么红黑树,映射(file,swap),共享内存,访问权限等等都由它来完成。这些在其他篇幅中有详细介绍。

本文来源:图解鸿蒙源码逐行注释分析

评论

您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
发文章