提问人:TheMemeMachine 提问时间:8/10/2023 最后编辑:tadmanTheMemeMachine 更新时间:8/10/2023 访问量:100
如何确定 C 程序中的可用堆内存
How to determine available heap memory in a C program
问:
我想编写一个程序,每秒分配一些内存块,然后写出剩余的内存量(我故意不释放任何内存,因为实际用例是模拟内存不足的情况)。这是程序(适用于 linux):
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
size_t mbs = 500 * 1000000; // 500mb
while(true) {
sleep(1);
void* tmp = malloc(mbs);
system("free");
}
return 0;
}
系统调用列出可用内存,我预计可用内存每秒减少 500mb,我尝试分配,但是从下面的前几行输出中可以看出,可用内存没有显着变化(在大约 32gb 的 RAM 中, 可用内存徘徊在 25GB 左右)。我也尝试过较低的数量,10mb 和 100mb,但行为是一样的。
因此,在这个特定的输出中,到第 8 次空闲时,我预计已经使用了 8gbs 的 ram:free
user@DESKTOP-DAGF175:/Projects/tmp$ g++ main.cpp
user@DESKTOP-DAGF175:/Projects/tmp$ ./a.out
total used free shared buff/cache available
Mem: 33471660 7338384 25903924 17720 229352 25999544
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7330684 25911624 17720 229352 26007244
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7327256 25915052 17720 229352 26010672
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7325428 25916880 17720 229352 26012500
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7325208 25917100 17720 229352 26012720
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7321232 25921076 17720 229352 26016696
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7321360 25920948 17720 229352 26016568
Swap: 8192000 0 8192000
total used free shared buff/cache available
Mem: 33471660 7318624 25923684 17720 229352 26019304
Swap: 8192000 0 8192000
我也在Windows上尝试过类似的事情,但结果是一样的。这里也是 Windows 代码:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main() {
size_t mbs = 500 * 1000000; // 500mb
while(true) {
Sleep(2);
void* tmp = malloc(mbs);
system("systeminfo |find \"Available Physical Memory\"");
}
return 0;
}
为什么我没有看到消耗的内存减少?
答:
8赞
miloserdow
8/10/2023
#1
您观察到的行为是由于现代操作系统处理内存分配的方式造成的。当您使用 请求内存时,操作系统会保留虚拟内存地址,但不会立即分配物理内存页。malloc()
只有当程序写入内存时,操作系统才会将这些虚拟地址映射到物理内存页。
这种行为称为懒惰分配或过度承诺。操作系统向该过程承诺一些内存,直到绝对必要时才真正提供内存。
如果要观察可用内存的减少,则需要通过写入分配的内存来强制操作系统提交这些页面:
const int PAGE_SIZE = 4096; // commonly used page size
int main() {
size_t mbs = 500 * 1000000; // 500mb
while(true) {
sleep(1);
char* tmp = (char*)malloc(mbs);
if(tmp == NULL) {
printf("Allocation failed\n");
exit(1);
}
// Force the OS to commit the memory by writing to it
for(size_t i = 0; i < mbs; i += PAGE_SIZE) {
tmp[i] = 0;
}
system("free");
}
return 0;
}
编辑:此外,您可以使用接口在 Linux 中禁用过量使用:sysctl
echo 2 > /proc/sys/vm/overcommit_memory
有效设置:
0
对于启发式策略(内核将尝试估计用户空间分配的可用内存量)1
对于“始终过量使用”(内核允许所有内存分配,无论当前内存分配状态如何)2
用于禁用过量使用
评论
0赞
Andrew Henle
8/10/2023
如果要观察可用内存的减少或者,您可以禁用内存过量使用,并强制操作系统在未承诺允许其使用的情况下不提供内存。操作系统向该过程承诺了一些内存,直到绝对必要时才真正提供内存是的,如果你使用它,你可以得到,“哈哈!我撒谎了!你不可能真的拥有我答应过你的那种记忆!它是你的OOM杀手!!”如果你幸运的话,这是你的过程。如果你不走运,那就是主要的生产数据库进程或类似的进程。如果您关心持续可用性,内存过量使用是非常愚蠢的。
2赞
tadman
8/10/2023
我和安德鲁在一起。操作系统,就像一家距离破产只有一次发动机故障的廉价航空公司一样,可以而且会在很多事情上撒谎,尤其是它可以承诺分配多少内存。当它陷入谎言时,它只是终止指出问题的程序,从而解决问题!
1赞
Andrew Henle
8/10/2023
@tadman 当它陷入谎言时,它只是终止指出问题的程序......这就是问题所在 - Linux OOM 杀手不一定会终止指出问题的程序 - 如果你的关键生产进程使用了系统 128 GB RAM 中的 120 GB,并且你错误地登录并启动了该服务器上的 Eclipse,那么 OOM 杀手很可能会破坏你的生产过程。另请参阅 Fault-Of-Fuel Killer。如果燃油不足,你觉得乘坐一架把你扔出门外的飞机怎么样?欢迎使用 Linux。
1赞
tadman
8/10/2023
@AndrewHenle Linux 在内存不足时确实会变得有点杀人,这是真的。我见过它在精神病态的愤怒中杀死各种各样的东西,包括莫名其妙地,但是当你知道有很多自由记忆时,你可以高枕无忧,这还有什么附带损害。init
1赞
tadman
8/10/2023
@miloserdow我从来没有收到过OOMKiller的优惠券。只有页面和愤怒的客户。
评论