如何确定 C 程序中的可用堆内存

How to determine available heap memory in a C program

提问人:TheMemeMachine 提问时间:8/10/2023 最后编辑:tadmanTheMemeMachine 更新时间:8/10/2023 访问量:100

问:

我想编写一个程序,每秒分配一些内存块,然后写出剩余的内存量(我故意不释放任何内存,因为实际用例是模拟内存不足的情况)。这是程序(适用于 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;
}

为什么我没有看到消耗的内存减少?

C Linux 内存 malloc

评论

3赞 HolyBlackCat 8/10/2023
尝试将非零写入内存,以防在第一次写入时延迟分配。另外,请注意,对使用的内存可能没有硬性限制,因为在用完所有交换之前,您的系统会变慢到爬行。

答:

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的优惠券。只有页面和愤怒的客户。