生动形象的解释下虚拟内存和物理内存的区别并且详情解释下是如何升高和降低的虚拟内存的


一、虚拟内存和物理内存的生动比喻

想象你有一个书桌和一个图书馆

  • 物理内存(RAM) 就像你的书桌,桌面空间有限,能放的书和资料有限。
  • 虚拟内存 就像你在图书馆的借书卡,虽然桌面空间有限,但你可以通过借书卡从图书馆借来很多书,感觉自己“拥有”了比桌面更大的空间。

具体说明:

  • 你的电脑或手机运行程序时,程序需要用内存来存放数据和代码。
  • 物理内存(书桌)是实际存在的快速存储空间,访问速度快,但容量有限。
  • 虚拟内存(借书卡)是操作系统给每个程序分配的“假象”内存空间,程序看到的是一个很大的连续空间,不必关心物理内存的大小和分布。
  • 当程序需要的数据不在书桌上时,操作系统会从图书馆(硬盘或压缩内存)取书放到书桌上,或者把书桌上的书放回图书馆腾出空间。

二、虚拟内存是如何升高和降低的?


1. 虚拟内存“升高”——为什么虚拟内存会变大?

继续用书桌和图书馆的比喻:

  • 当你开始做一个项目(运行一个程序),你会把需要的书(内存页)放到书桌上。
  • 如果项目变复杂了,你需要查阅更多的书,桌面上的书就会越来越多。
  • 这时,你的“借书卡”允许你“借”更多的书,虚拟内存空间就“升高”了。

在系统层面,虚拟内存升高的原因包括:

  • 程序申请更多内存:调用mallocnewmmap等接口申请内存。
  • 加载更多模块或库:程序运行时加载更多动态库或资源文件。
  • 内存映射文件增多:映射大文件到内存。
  • 内存泄漏:程序没有释放不再使用的内存,导致虚拟内存持续增长。

2. 虚拟内存“降低”——虚拟内存是如何减少的?

回到比喻:

  • 当你完成某个项目或不再需要某些书时,你会把书收起来,腾出桌面空间。
  • 你也可能把不常用的书放回图书馆,保持桌面整洁。
  • 这样,桌面上的书(虚拟内存)数量就减少了。

在系统层面,虚拟内存降低的方式包括:

  • 程序释放内存:调用freemunmap等接口释放内存。
  • 垃圾回收:Java、Kotlin等语言的GC机制回收无用对象。
  • 内存映射解除:调用munmap解除文件映射。
  • 系统回收:操作系统通过Low Memory Killer杀死后台进程,释放内存。
  • 内存压缩和交换:使用zRAM压缩内存,或者将部分内存页换出到磁盘(传统swap)。

三、总结

方面书桌和图书馆比喻系统层面对应
物理内存书桌,有限的实际空间RAM,实际的高速内存
虚拟内存借书卡,感觉拥有比书桌更大的空间操作系统给程序的虚拟地址空间
虚拟内存升高需要更多书,桌面上放更多书程序申请更多内存,加载更多资源
虚拟内存降低收起书,腾出桌面空间程序释放内存,系统回收,内存映射解除

我继续帮你深入讲解虚拟内存升高和降低的具体机制,并结合一些技术细节和实际操作,帮助你更全面理解。


四、虚拟内存升高的具体机制

虚拟内存的“升高”本质上是进程的虚拟地址空间被分配和使用的过程。具体来说:

1. 进程申请内存

  • 堆内存增长
    程序通过mallocnew等接口申请堆内存,操作系统会在虚拟地址空间中为堆分配新的区域。

    • 堆的增长通常是连续的,操作系统通过brkmmap系统调用扩展堆空间。
    • 这会使虚拟内存峰值升高。
  • 栈内存增长
    每个线程有自己的栈,栈空间会根据函数调用深度动态增长。

    • 栈的增长也会占用虚拟内存空间。
  • 内存映射(mmap)
    程序通过mmap映射文件或匿名内存,映射区域会占用虚拟地址空间。

    • 例如加载动态库、映射大文件、分配匿名内存等。
    • 这部分虚拟内存通常不连续,且可能很大。

2. 资源加载

  • 动态库加载
    程序运行时加载的.so文件会映射到虚拟内存。
  • 大对象和缓存
    比如图片、视频缓冲区等大对象,会占用大量虚拟内存。

3. 内存泄漏

  • 程序未释放不再使用的内存,导致虚拟内存持续增长。
  • Native层泄漏尤为严重,因为GC无法管理。

五、虚拟内存降低的具体机制

虚拟内存降低,意味着进程释放了部分虚拟地址空间,具体方式包括:

1. 释放堆内存

  • 程序调用freedelete释放堆内存。
  • 如果释放的是堆尾部的内存,操作系统可能通过brk收缩堆空间,减少虚拟内存。
  • 对于中间区域释放,内存会被标记为可用,但虚拟地址空间大小不一定减少。

2. 解除内存映射

  • 调用munmap解除文件或匿名内存映射,释放对应虚拟地址空间。
  • 这通常能显著降低虚拟内存峰值。

3. 垃圾回收(GC)

  • Java/Kotlin等语言的GC回收无用对象,释放堆内存。
  • GC后,部分内存会被释放回操作系统,虚拟内存峰值降低。

4. 进程退出或被杀死

  • 进程结束时,操作系统回收所有虚拟内存。
  • LMK杀死后台进程,释放内存压力。

六、虚拟内存升高和降低的系统视角


操作类型系统调用/机制虚拟内存变化备注
申请堆内存brkmmap虚拟内存升高堆空间扩展
释放堆内存free + brk收缩虚拟内存降低(仅尾部收缩)中间释放不一定减少虚拟内存
映射文件mmap虚拟内存升高动态库、资源文件映射
解除映射munmap虚拟内存降低释放映射区域
线程栈增长自动增长虚拟内存升高递归调用、深度调用导致栈增长
线程栈释放线程结束虚拟内存降低线程退出释放栈空间
GC回收JVM GC虚拟内存降低释放Java堆内存
进程结束进程退出虚拟内存归零操作系统回收所有资源

七、实际操作示例


1. 查看进程虚拟内存使用

adb shell cat /proc/<pid>/status | grep VmPeak
  • VmPeak表示进程历史最高虚拟内存使用量。

2. 观察内存映射

adb shell cat /proc/<pid>/maps
  • 查看进程当前所有虚拟内存映射区域。

3. 申请和释放内存示例(C语言)

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    printf("Initial brk: %p\n", sbrk(0));

    // 申请10MB堆内存
    void* p = malloc(10 * 1024 * 1024);
    printf("After malloc brk: %p\n", sbrk(0));

    // 释放内存
    free(p);
    printf("After free brk: %p\n", sbrk(0));

    return 0;
}
  • 你会发现brk指针(堆顶)在malloc后升高,free后不一定降低,除非调用malloc_trim或程序主动收缩堆。

八、总结

  • 虚拟内存是程序看到的地址空间,物理内存是实际的硬件内存。
  • 虚拟内存升高主要由程序申请内存、映射文件、加载库等行为引起。
  • 虚拟内存降低主要由程序释放内存、解除映射、GC回收和进程退出引起。
  • 虚拟内存峰值高不一定马上导致物理内存耗尽,但持续升高会增加OOM风险。
  • 合理管理内存申请和释放,及时解除映射,是控制虚拟内存峰值的关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值