如何检查 Linux 上进程的堆大小

2024-01-07

我正在编写一些代码,但它一直崩溃。后来在挖掘转储后,我意识到我超出了最大堆限制(如果我添加了对 malloc 的检查,生活会更容易)。尽管我修复了这个问题,有什么方法可以增加我的堆大小吗?

PS:相当类似的问题 https://stackoverflow.com/questions/2354507/how-to-find-size-of-heap-present-in-linux在这里,但我不清楚回复。


堆和内存管理是 C 库(可能是 glibc)提供的功能。它会维护堆并在每次执行操作时将内存块返回给您malloc()。它不知道堆大小限制:每次您请求的内存超过堆上可用的内存时,它都会向内核请求更多内存(使用sbrk() or mmap()).

默认情况下,当需要时,内核几乎总是会为您提供更多内存。这意味着malloc()将始终返回有效地址。只有当您第一次引用分配的页面时,内核才会真正为您查找页面。如果它发现它无法给你一个,它就会运行一个 OOM 杀手,根据某种措施称为badness(其中包括您的进程及其子进程的虚拟内存大小、良好级别、总体运行时间等)选择受害者并向其发送SIGTERM。这种内存管理技术称为过量使用,由内核在以下情况下使用:/proc/sys/vm/overcommit_memory是 0 或 1。参见过度使用会计 http://www.mjmwired.net/kernel/Documentation/vm/overcommit-accounting有关详细信息,请参阅内核文档。

通过将 2 写入/proc/sys/vm/overcommit_memory您可以禁用过量使用。如果你这样做,内核实际上会在承诺之前检查它是否有内存。这将导致malloc()如果没有更多内存可用,则返回 NULL。

您还可以设置进程可以分配的虚拟内存的限制setrlimit() and RLIMIT_AS或与ulimit -v命令。无论上述过度使用设置如何,如果进程尝试分配超过限制的内存,内核将拒绝它并malloc()将返回 NULL。请注意现代 Linux 内核(包括整个 2.6.x 系列)对驻留大小的限制(setrlimit() with RLIMIT_RSS or ulimit -m命令)无效。

下面的会话在内核 2.6.32 上运行,具有 4GB RAM 和 8GB 交换空间。

$ cat bigmem.c
#include <stdlib.h>
#include <stdio.h>

int main() {
  int i = 0;
  for (; i < 13*1024; i++) {
    void* p = malloc(1024*1024);
    if (p == NULL) {
      fprintf(stderr, "malloc() returned NULL on %dth request\n", i);
      return 1;
    }
  }
  printf("Allocated it all\n");
  return 0;
}
$ cc -o bigmem bigmem.c
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ sudo bash -c "echo 2 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
2
$ ./bigmem
malloc() returned NULL on 8519th request
$ sudo bash -c "echo 0 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ ulimit -v $(( 1024*1024 ))
$ ./bigmem
malloc() returned NULL on 1026th request
$

在上面的示例中,交换或 OOM 终止永远不会发生,但如果进程实际上尝试接触所有分配的内存,情况就会发生重大变化。

直接回答你的问题:除非你明确设置了虚拟内存限制ulimit -v命令,除了机器的物理资源或地址空间的逻辑限制(与 32 位系统相关)之外,没有堆大小限制。你的 glibc 将继续在堆上分配内存,并随着堆的增长向内核请求越来越多的内存。如果所有物理内存都耗尽,最终可能会导致交换效果不佳。一旦交换空间耗尽,内核的 OOM 杀手就会杀死一个随机进程。

但请注意,除了缺少可用内存、碎片或达到配置的限制之外,内存分配失败的原因可能还有很多。这sbrk() and mmap()glib 分配器使用的调用有其自身的失败,例如程序中断到达另一个已分配的地址(例如共享内存或先前映射的页面)mmap())或已超出进程的最大内存映射数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何检查 Linux 上进程的堆大小 的相关文章

随机推荐