linux mmu的实现的讲解_linux 虚拟内存

前面讲了单纯的操作系统的虚拟内存、linux进程的虚拟地址,然后又讲了linux的进程的内存布局,其实那张图就是linux进程的虚拟内存。

7c85fc4149a2d9c037d89e24a80ef07a.png
取自:https://blog.csdn.net/dlutbrucezhang/article/details/9058583

可是感觉理解不够,所以再来学习: 下面这部分是参考这个视频学习的:

https://www.bilibili.com/video/av42496297?from=search&seid=1238971517368934147 这个说的是linux的 swap

这称为交换过程。这样你的linux系统就可以释放一些ram空间,并且由于缺乏内存不会崩溃。因为 linux swap是扩展ram的一种非常有用的方法,因为它提供了必要的ram空间耗尽且必须继续进程时的额外内存。所以这就是为什么你安装linux的时候会提示你要为交换linux内核通常使用RAM内存来存储临时信息,当没有足够的ram空间时,linux内核会从中获取一些ram信息,并将其写入硬盘驱动器上的交换空间。分区分配空间。如下图:

99cdf5ddc860972c6d69ebbb4075cf35.png

我们需要linux swap吗?

通常你的ram已满并且linux内核没有可写空间时,你的系统将崩溃。但如果你有交换分区,那么linux内核和程序会使用它,所以你的程序不会崩溃,可以继续工作但是速度会慢很多。因此,拥有交换空间更安全。

交换分区有一个缺点:它比ram慢很多,因此,添加交换空间不会使你的计算机运行速度更快,它只会帮助克服一些ram大小带来的限制。

交换空间有两个选项:交换分区和交换文件。

交换分区是硬盘驱动器的一部分,他是为交换空间保留的。

交换分区的大小:

1g ram----2g swap

2-4g ram ----2-4g swap

8g ram ---- 4g swap

>8g -----2-4g swap

(我的win10是4g内存,8g虚拟内存,阿里云上的linux swapon没有反应)

我看完后发现,这个和虚拟内存的思想很像很像,可是又没有确定的解释它和linux的虚拟内存的关系。看来了解的还是太少了。

然后来看下一个视频:这个内容不错

学习于:https://www.bilibili.com/video/av32735338/

下面是核心图:大家放大看会更好一些:

2bfb1bd7e14162235cf7decebe3baa1f.png

高级语言的程序代码,经过编译链接后,编程二进制的机器码存储在计算机的外存中。每个进程的代码都有它的地址。这些机器指令序列是分页存储的,一般是4kb。就这样一页一页地排在外存中。然后要运行的页面就加载进内存中,不运行的就放在外存中。然后在每个进程的内核空间里都存在着页表,页表里存储此进程的程序页的编号,是否在内存,程序页的在此进程中的虚拟地址,程序页的物理内存地址,程序页的外存地址。如果该程序页在内存中,就没有外存地址。

然后看cpu是怎么执行指令的。

cpu运行一个进程的时候,要去取下一条指令的地址。这时候它收到的地址是进程传过来的进程的虚拟地址,也就是说指令地址寄存器pc存放的是虚拟地址,然后经过MMU(memory manager unit)内存管理单元,MMU先通过该进程的页表检查指令所在页是否在内存中,如果是,则直接去内存中去页表里的内存地址取出指令,然后执行。如果不在内存中,就去外存中找到该指令,把指令先加载到内存中,再将虚拟地址转为内存地址,再从内存中取出指令执行,然后更新页表。

这里强调:虚拟内存是指针对cpu而言,cpu处理的是进程里的虚拟地址,而不是操作具体的物理地址。也就是说cpu看到的是只是虚拟地址,所以cpu认为这个虚拟地址对应这个内存,而这个内存是不存在的,所以我们认为这是虚拟内存。

(这位老师的说的页面置换原则是只要页面没运行,就置换出外存,而操作系统课上有很多的页面置换算法,比如LRU,FIFO之类的,这方面我不太清楚,但是这里的思想感觉是没错的,也很细致了)

至于缺页中断,tlb,局部性原理提高命中那方面的知识,前面的文章已经讲过了,就不再这重复了。对了,这里提醒一下,进程的内核空间应该是存储在内存中的,而且各个进程的内核空间对应的都是内存中的同一个内核空间。里面分别有各个进程的pcb,页表等东西。

看完后我就产生了其它方面的疑问:置换出去的都是用户空间的代码段和数据段吗?代码段和数据段很大吗?

下面是参考《深入理解计算机系统》:

虚拟内存的三个重要的能力:

1.它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效地使用了主存。

2.它为每个进程提供了一致的地址空间,从而简化了内存管理。

3.它保护了每个进程的地址空间不被其它进程破坏。

后面看:腾讯云技术社区:十问 Linux 虚拟内存管理 (glibc) (一) 又学到了一波东西。

这里摘录一些思考和笔记:

第一个理解:

进程使用多少内存可通过 ps aux 命令 查看,其中关键的两信息(第五、六列)为:

  1. VSZ , virtual memory size ,表示进程总共使用的虚拟地址空间大小,包括进程地址空间的代码段、数据段、堆、文件映射区域、栈、内核空间等所有虚拟地址使用的总和,单位是 K
  2. RSS , resident set size ,表示进程实际使用的物理内存空间, RSS 总小于 VSZ

然后结合图片一看:

361228bb103d99c600ed50655e61ce30.png

观察一下,进程占用的虚拟内存一般都多大,大的比如里面的java进程是2.5个G 这样,小的就几十M,比如nginx的进程。而看实际物理内存,最大的就java的266M。这里综合一下4G的模型,所以在这里理解都是4G是针对程序而言的,涉及到多级页表的知识。

然后是下一个理解:

malloc 是 glibc 中内存分配函数,也是最常用的动态内存分配函数,其内存必须通过 free 进行释放,否则导致内存泄露。

关于 malloc 获得虚存空间的实现,与 glibc 的版本有关,但大体逻辑是:

  1. 若分配内存小于 128k ,调用 sbrk() ,将堆顶指针向高地址移动,获得新的虚存空间。
  2. 若分配内存大于 128k ,调用 mmap() ,在文件映射区域中分配匿名虚存空间。
  3. 这里讨论的是简单情况,如果涉及并发可能会复杂一些,不过先不讨论。

其中 sbrk 就是修改栈顶指针位置,而 mmap 可用于生成文件的映射以及匿名页面的内存,这里指的是匿名页面。

而这个 128k ,是 glibc 的默认配置

从这里我们可以得到的信息是:内存分配和置换不只是指令代码,还包括对象,数据之类的。只要是暂时没用到的都可以把该page置换出去。

下一个理解:

  1. VSZ 并不是每次 malloc 后都增长,是与上一节说的堆顶没发生变化有关,因为可重用堆顶内剩余的空间,这样的 malloc 是很轻量快速的。
  2. 但如果 VSZ 发生变化,基本与分配内存量相当,因为 VSZ 是计算虚拟地址空间总大小。
  3. RSS 的增量很少,是因为 malloc 分配的内存并不就马上分配实际存储空间,只有第一次使用,如第一次 memset 后才会分配。(也就是使用才分配的原则,符合虚拟内存的原理)
  4. 由于每个物理内存页面大小是 4k ,不管 memset 其中的 1k 还是 5k 、 7k ,实际占用物理内存总是 4k 的倍数。所以 RSS 的增量总是 4k 的倍数
  5. 因此,不是 malloc 后就马上占用实际内存,而是第一次使用时发现虚存对应的物理页面未分配,产生缺页中断,才真正分配物理页面,同时更新进程页面的映射关系(也就是页表)。这也是 Linux 虚拟内存管理的核心概念之一。(结合前面的知识,也就是基本上都是malloc后就放在虚拟内存当中,然后用上了再加载到物理内存)

疑问:究竟linux的虚拟内存的页面置换算法是怎么实现的呢?似乎需要看源码啊

嗯,差不多就到这里吧。感觉还是得慢慢研究《深入理解计算机系统》这本书啊。这本书才是权威,看网上的很多都不太靠谱。但是这本书有点难读,后面慢慢来吧。。。

欢迎交流讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值