我从一个程序启动了 700 多个线程,我的/proc/[PID]/status
文件显示了以下输出。
VmPeak: 7228104 kB
VmSize: 7228104 kB
VmLck: 0 kB
VmHWM: 3456 kB
VmRSS: 3456 kB
VmData: 7222340 kB
VmStk: 88 kB
VmExe: 4 kB
VmLib: 1540 kB
VmPTE: 2864 kB
StaBrk: 15e84000 kB
Brk: 15ec6000 kB
StaStk: 7fff765095a0 kB
Threads: 706
但我只有 2GB RAM 和 4GB 交换空间。有人能告诉我虚拟内存是如何达到7GB+的吗?
答案1
在某些请求分页虚拟内存系统上,操作系统拒绝分配匿名页面(即包含没有文件系统源的数据的页面,例如运行时数据、程序堆栈等),除非有足够的交换空间来交换这些页面以便释放物理内存。这种严格计算的优点是保证每个进程都能访问它们分配的尽可能多的虚拟内存,但这也意味着可用的虚拟内存量本质上受到交换空间大小的限制。
实际上,程序分配的内存往往多于其使用的内存。例如,Java虚拟机在启动时分配大量虚拟内存,但不会立即使用它。 Linux 内核中的内存统计尝试通过跟踪进程实际使用的内存量来弥补这一点,并过度使用虚拟内存量。换句话说,内核分配的虚拟内存量可能超过系统上物理内存和交换空间的总和。虽然这可以更好地利用物理内存和交换空间,但缺点是当使用的内存量超过可用的物理内存和交换空间量时,内核必须以某种方式释放内存资源以满足内存分配承诺。
用于回收内存的内核机制称为内存不足杀手(OOM 杀手)。通常,该机制将开始杀死占用内存的“流氓”进程,为其他进程释放内存。在某些环境中,释放内存并使系统恢复运行的一个可行选择是重新启动。对于这些情况,可以通过 sysctl 设置将内核配置为在内存不足的情况下出现紧急情况vm.panic_on_oom
。
内核使用的内存计算启发式可以通过vm.overcommit_memory
sysctl 设置变得更加自由或严格。当使用严格的内存统计时,内核将不再分配匿名页面,除非它有足够的可用物理内存或交换空间来存储页面。这意味着该系统必须配置了足够的交换空间。
答案2
作为一个切线点,如果创建了线程并且线程函数在完成其工作后退出,但 VmDATA 不断增加,那么就会出现内存泄漏。
通常,当线程函数退出时,pthread_exit 是隐式的,但线程资源直到 pthread_join 或 pthread_detach 才会释放。因此,要显式地从堆中释放线程堆栈并关闭泄漏,请显式调用 join 或 detach。
答案3
这是因为虚拟内存并不是进程实际使用的内存,它只是进程使用其分配的所有内存时可能使用的内存。
网上有大量关于“虚拟内存”一词的描述,因为这是一个常见的混淆话题,这是其中之一:http://en.wikipedia.org/wiki/Virtual_memory
这个是针对 Linux 的更具体的:http://www.tldp.org/LDP/tlk/mm/memory.html