【涨知识】OS下的内存使用原来这么复杂
1、聊一聊
2、MCU与OS上内存的使用
下面是MCU与OS_PC的应用程序简易存储分布:
解析一下:
1)玩单片机的小伙伴应该都知道C语言中全局变量、静态变量都是存储在外部RAM里面的,这里的RAM可以认为就是MCU的内存,在平时进行裸机开发的时候如果不涉及到内存管理,基本上一块内存的使用都是固定不变且一一对应的,一旦内存使用完毕,则只能通过优化内存挤出所需的内存大小来进行使用。
2)然而像linux、window等等大型OS,其应用程序所需的内存是可以大于实际的物理内存的,应该很多小伙伴想到了通过分时复用内存可以提高内存的利用率,不过其代价就是需要牺牲时间来换取空间,然而对于强大的CPU确实能够在牺牲一些性能来获得更高的内存利用率,同时还有硬件MMU支持,更是成为了可能,从上图我们可以看到部分进程被置换到了外存中。然而对于MCU的性能相对较弱且相对应用比较单一,所以没有太多必要为了提高内存利用率而牺牲性能。
3)下面我们来了解一下大型OS如何管理内存。
3、OS为每个应用程序提供统一环境
前面我们提到过系统调用,OS为上层应用程序非常好的隐蔽了硬件,同样对于内存这个硬件的使用OS也为你安排好了。
1)虚拟地址与物理地址
对于应用程序而言其程序运行使用的地址均为虚拟地址(可以说CPU访问的地址均为虚拟地址),比如32位系统其虚拟地址大小为4G内存,而实际内存上的地址为物理地址,应用程序使用虚拟地址通过MMU硬件模块(可以认为就是一个地址转化模块,或者认为就是一个表)转化为物理地址来对实际的内存来进行访问。
解析一下:
从图上看只要OS能够管理好MMU应用程序便可以拥有相同的虚拟地址空间且不会相互影响,还可以通过检测相关内存地址是否正确起到保护的作用,同时对于编译、链接也带来了极大的便利。
所以这里的虚拟地址并不一定实实在在对应物理地址,OS可以通过置换技术使得"骗过"应用程序使其认为存在比物理内存还要大的内存空间来进行使用。
而MCU基本上都是直接使用的RAM物理地址,这样对于程序的可移植性带来限制。
2)连续与非连续内存分配
内存分配对于玩RTOS或者研究过malloc的小伙伴应该算比较熟悉,内核或者应用程序都有着动态分配内存的需求,而对于动态内存分配其主要解决的问题是内存碎片和分配与回收效率问题,这样就产生了各种算法,对于应用场景不同又分为连续内存分配和非连续内存分配:
连续内存分配:
1)使用直接分配内存会导致内存碎片(如下图内存2),如果以后用户所需的内存都比内存2大,那么这样内存2就成为了碎片。
2)为了解决碎片问题,大家又提出了碎片整理、置换分区等等,不过其处理都相对比较麻烦,对CPU性能影响较大,目前使用较广泛的是伙伴算法(Buddy)和slab分配器,其中伙伴算法个人平时就叫"二分法",其分配内存块较大最小单位为1页,且仅仅只能优化页之间的碎片,对于更小的内存分配无能为力,于是便采用slab分配器配合伙伴算法来优化页内碎片(slab分配器是在伙伴算法的页内进行内存管理)。
3)同时连续内存分配由于是一段连续的空间,这样通过高速缓存能够获得更高的访问效率。
非连续内存分配:
1)对于连续存储其物理地址连续容易导致碎片,并且对于数据的共享等相对比较困难,所以为了提高内存利用率和管理灵活,就产生了非连续存储分配,该分配方式是一种离散内存分配,所以必须要有对应的映射表(简单的说就是形成虚拟地址与物理地址的表格),便产生了段式、页式等管理结构。
2)因为查表也是需要消耗时间的,所以不可能每个地址都对应一个表项,那样建立的表太大,且查询效率较低,所以像Linux都会使用页为单位(4K)来建立映射表,那么虚拟地址和物理地址都是以最小单位1页来进行映射的,页内肯定也是连续的。
3)所以效率相对连续内存分配有所降低,为了加快查表速度实现高效访问又产生了提高效率的方式比如增加块表和多级页表等等,非连续存储能够避免外碎片不过会增加访问效率,对于访问不是很频繁的使用场景就非常有用了。
3)缺页机制与置换
缺页机制和置换就是实现逻辑地址空间比物理地址空间大的手段,因为我们的物理内存毕竟是有限的,而软件对内存的需求确实无止境的,程序的执行是一个局部性的事件(也就是程序局部性原理),这样就为时间换空间提供了可能。
1)从上图看来OS把进程的一部分搬移到了磁盘上,这样就获得更多的内存空间,形成了虚拟存储,如果频繁的搬移肯定会造成性能降低,而程序的局部性原理很好的降低了该情况的概率,因为程序大部分都是顺序执行,或者是在一定的区域内执行,这样想想,为什么MCU不进行这样的处理呢?1)硬件结构不支持;2)性能不够,搬移开销太大。
2)当页表中查询不到会产生缺页异常,在对换区(swap)中找到在磁盘中对应的页,并搬移到内存,然后修改页表项重新执行对应指令,如果当前内存中没有可用内存位置就需要把相关不常用的页移到磁盘进行置换。
3)上面提到暂时不用的代码或者数据会被置换到磁盘,如何识别暂时不用或者使用不频繁的页项又成为了一个技术问题,从而产生了一堆置换算法,后面有时间再根据具体的算法进行分析解读,这里就不再展开了。
4、最后小节
这里只是简单带大家了解一下OS对内存的管理和使用,大家可以细细评味一下计算机的魅力,对里面感兴趣的部分可以查阅相关教材进行阅读学习,后续作者也会安排一些不错的话题跟大家分享讨论,同时这里推荐一本书籍《深入理解Linux内核》第三版,非常值得学习一下。
好了,这里是公众号:“最后一个bug”,一个为大家打造的技术知识提升基地。同时非常感谢各位小伙伴的支持,我们下期精彩见!
推荐好文 点击蓝色字体即可跳转