虚拟内存与Swap机制探究
现代操作系统几乎都采用了虚拟内存机制,从一个常见的问题引出:在 4GB 物理内存的机器上,申请 8G 内存会怎么样呢?回答这个问题是需要具体情况分别看待的,来看看不同的机器、不同的Swap机制会有怎样的答案。
虚拟内存分布
对于32位操作系统,32根地址线最大能访问到的内存只有4GB,其内核空间占用1G,位于最高处,3G用户空间;
对于64位操作系统,内核空间和用户空间都是128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的;
根据这个内存分布情况,如果直接在32位操作系统申请8GB内存,那么会直接报错,因为进程之只能申请到3GB的空间,所以在申请阶段就会失败。所以不管有没有开启Swap机制,申请内存大小超过3GB就会报错。
所以对于32位操作系统,申请 8G 内存会直接报错!
申请内存流程
在Linux上申请内存时,申请到的是虚拟内存,此时还并未分配对应的物理内存,只有这块内存发生了读写操作的时候,会发现这个虚拟内存没有映射到物理内存, CPU 就会产生缺页中断,进程会从用户态切换到内核态,并将缺页中断交给内核的缺页中断函数来处理:如果有就直接分配物理内存,并在页表建立映射关系;如果不够就会触发GC(此处的GC是指内核进行的内存垃圾回收),然后如果有就直接分配物理内存,没有则发生OOM!
64位系统情况
那么现在来看看64位操作系统的情况:
对于64位操作系统,进程可以使用 128 TB 大小的虚拟内存空间,所以进程申请 8GB 内存是没问题的,因为进程申请内存是申请虚拟内存,只要不读写这个虚拟内存,操作系统就不会分配物理内存。
1#include <stdio.h>
2#include <stdlib.h>
3
4int main(){
5 for(int i = 0; i < 4; i++){
6 malloc(1024 * 1024 * 1024);
7 }
8 while(1);
9 return 0;
10}
开始编译、执行:
其中VSZ 就代表进程使用的虚拟内存大小,RSS 代表进程使用的物理内存大小,可以看出虚拟内存申请了4GB,物理内存使用了348字节!
我的云服务器内存大小是2GB,可见申请4GB内存也是OK的!
Swap机制
当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间会被临时保存到磁盘,等到那些程序要运行时,再从磁盘中恢复保存的数据到内存中。
Swap 就是把一块磁盘空间或者本地文件,当成内存来使用,它包含换出和换入两个过程:
- 换出(Swap Out),是把进程暂时不用的内存数据存储到磁盘中,并释放这些数据占用的内存;
- 换入(Swap In),是在进程再次访问这些内存的时候,把它们从磁盘读到内存中来;
Linux 中的 Swap 机制会在内存不足和内存闲置的场景下触发,kswapd 是 Linux 负责页面置换的守护进程,它也是负责交换闲置内存的主要进程:
最终结论
1、在 32 位操作系统,因为进程最大只能申请 3 GB 大小的虚拟内存,所以直接申请 8G 内存,会申请失败。
2、在 64位 位操作系统,因为进程最大只能申请 128 TB 大小的虚拟内存,即使物理内存只有 4GB,申请 8G 内存也是没问题,因为申请的内存是虚拟内存。但是如果这块虚拟内存被访问了,要看系统有没有 swap 分区:
- 没有 swap 分区:那就看物理内存够不够大了,不够的话会OOM
- 有 swap 分区:要看swap分区有多大,如果实际使用中如果swap分区也不够用了,也会OOM