操作系统虚拟内存
我们需要先来了解不同位的操作系统的虚拟内存大小。
32 位操作系统和 64 位操作系统的虚拟地址空间大小是不同的
在 Linux 操作系统中,虚拟地址空间的内部又被分为 内核空间 和 用户空间两部分
用户空间: 大约是3GB,用于存放用户级应用程序的代码和数据。这是用户应用程序可以访问的部分地址空间。
内核空间: 剩余的约1GB,用于操作系统内核的代码和数据。只有操作系统内核可以访问内核空间,而用户应用程序不能直接访问它。
所以说,我们最大能申请的虚拟内存的大小需要根据操作系统位来判断。
mac 可以用 uname -m
查看
“x86_64”,则表示系统是 64 位的,如果看到 “i386”,则表示系统是 32 位的。
32 位系统:最大能申请3G的虚拟内存
64位系统: 最大能申请128T的虚拟内存
所以,我们了解了第一个影响虚拟内存大小的点:操作系统的位数
现在我们可以回答了其中一种情况:
在 32 位操作系统、4GB 物理内存的机器上,申请 12GB 内存,会怎么样?
因为 32 位操作系统,进程最多只能申请 3 GB 大小的虚拟内存空间,所以进程申请 12GB 内存的话,在申请虚拟内存阶段就会失败。
操作系统访问虚拟内存过程
我们用 c 语言分配内存的时候,都会用到 malloc 函数。
应用程序通过 malloc 函数申请内存的时候,实际上申请的是虚拟内存,此时并不会分配物理内存。
当应用程序读写了这块虚拟内存,
- CPU 就会去访问这个虚拟内存,
- 如果发现这个虚拟内存没有映射到物理内存, CPU 就会产生 缺页 中断,进程会从用户态切换到内核态,并将缺页中断交给内核的处理。
- 缺页中断处理函数会看是否有空闲的物理内存:
1.1 . 如果有,就直接分配物理内存,并建立虚拟内存与物理内存之间的映射关系。
2.2 如果没有空闲的物理内存,那么内核就会开始进行回收内存 的工作,如果回收内存工作结束后,空闲的物理内存仍然无法满足此次物理内存的申请,那么内核就会触发 OOM (Out of Memory)。
我们可以看到,如果访问了虚拟内存,就会开始分配物理内存。
那么假如我们分配了虚拟内存,不访问呢?
没错, 只要不读写这个虚拟内存,操作系统就不会分配物理内存。
所以我们可以明白: 在 64 位操作系统、4GB 物理内存的机器上,申请 12G 内存,会怎么样?
64 位操作系统,进程可以使用 128 TB 大小的虚拟内存空间, 所以进程申请 12GB 内存是没问题的 ,因为进程申请内存是申请虚拟内存,并没有读写。
总结
先总结一下上面的知识,
- 在 32 位操作系统,因为进程最大只能申请 3 GB 大小的虚拟内存,所以直接申请 8G 内存,会申请失败。
- 在 64 位操作系统,因为进程最大只能申请 128 TB 大小的虚拟内存,即使物理内存只有 4GB,申请 12G 内存也是没问题,因为申请的内存是虚拟内存。
程序申请的虚拟内存,如果没有被使用,它是不会占用物理空间的。当访问这块虚拟内存后,操作系统才会进行物理内存分配。
如果申请物理内存大小超过了空闲物理内存大小呢?
其实在 OOM 前还有还有一个检查: 是否开启 Swap 机制
什么是 Swap 机制?
当内存使用存在压力的时候,会开始触发内存回收行为,会把这些不常访问的内存先写到磁盘中,然后释放这些内存,给其他更需要的进程使用。再次访问这些内存时,重新从磁盘读入内存就可以了。
这种,将内存数据换出磁盘,又从磁盘中恢复数据到内存的过程,就是 Swap 机制负责的。
所以:
- 如果没有开启 Swap 机制,程序就会直接 OOM;
- 如果有开启 Swap 机制,程序可以正常运行。
总结:
分配虚拟内存空间,考虑三个条件:
- 操作系统是 32 位的,还是 64 位的
- 申请完 8G 内存后会不会被使用?
- 操作系统有没有使用 Swap 机制?