内存吞噬者为何不吞噬内存?虚拟内存与物理内存揭秘
2024-03-10 07:23:42
内存的真面目:为什么内存吞噬者并不吞噬内存
导言
在当今数字时代,内存是各种设备和系统中必不可少的元素。然而,高效管理内存对于优化性能和避免系统崩溃至关重要。本文将探讨一个看似违反常理的现象:一个宣称消耗大量内存的程序,实际上并没有真正消耗内存。
问题分析
我们从一个旨在模拟 Unix 服务器上内存不足 (OOM) 情况的程序入手。该程序不断分配和释放内存以模拟内存消耗。令人惊讶的是,即使在物理内存匮乏的系统上,该程序也未能实际消耗内存。
代码审查
下面是程序代码的简化版本:
unsigned long long memory_to_eat = 1024 * 50000;
void *memory = NULL;
int eat_kilobyte()
{
memory = realloc(memory, ...);
}
int main()
{
...
while (memory_to_eat > 0) {
memory_to_eat--;
if (eat_kilobyte()) {
return 200;
}
...
}
...
}
系统设置
该程序在启用了 overcommit 的 Linux 系统上运行。Overcommit 允许程序分配比实际可用物理内存更多的虚拟内存。
揭开谜底
1. 虚拟内存与物理内存
该程序分配的不是物理内存,而是虚拟内存。虚拟内存是一种技术,它允许程序访问比实际物理内存更大的地址空间。当程序分配虚拟内存时,操作系统会在磁盘上创建一个称为页面文件的特殊文件,用于存储内存内容。
2. Overcommit
启用了 overcommit 时,操作系统允许程序分配比实际可用物理内存更多的虚拟内存。因此,当该程序分配 50 GB 的虚拟内存时,操作系统并不会立即分配 50 GB 的物理内存。
3. 内存映射
该程序使用 realloc() 函数来分配内存。realloc() 函数创建一个新的内存块,并将现有数据复制到新的内存块中。这意味着该程序并没有真正消耗它分配的虚拟内存。相反,操作系统创建了一个内存映射,将虚拟内存页映射到磁盘上的页面文件中。
结论
因此,尽管该程序分配了 50 GB 的虚拟内存,它实际上并没有消耗 50 GB 的物理内存。这是因为启用了 overcommit,并且程序分配的是虚拟内存,而不是物理内存。相反,它创建了一个内存映射,将虚拟内存页映射到磁盘上的页面文件中。
常见问题解答
-
为什么程序分配的虚拟内存没有立即分配物理内存?
- 启用 overcommit 后,操作系统允许程序分配比实际可用物理内存更多的虚拟内存。
-
内存映射是如何工作的?
- 内存映射将虚拟内存页映射到磁盘上的页面文件中。当程序访问虚拟内存页时,操作系统将从页面文件中提取数据。
-
overcommit 有什么好处?
- overcommit 允许程序分配更多内存,即使这些内存不在物理内存中。这可以提高程序的灵活性,并避免因内存不足而崩溃。
-
overcommit 有什么缺点?
- overcommit 可能会导致系统性能下降,因为当物理内存用尽时,操作系统需要将数据交换到磁盘中。
-
如何避免 overcommit 的负面影响?
- 监控内存使用情况并限制程序分配的虚拟内存量。