malloc失败后没有自由成功

Bar*_*uch 7 c malloc memory-management

我写了一个小程序来粗略估计堆大小(我知道我可能只是用谷歌搜索它,但这似乎更有趣,我认为这将是一个简单的事情).

这是整个计划:

#include <stdio.h>
#include <stdlib.h>

void main()
{
    unsigned long long alloc_size = 1024;
    unsigned long long total = 0;
    unsigned int i = 0;
    void* p = 0;

    while(alloc_size >= 16) {
        p = malloc(alloc_size);
        if (p) {
            total += alloc_size;
            i++;
            printf("%u)\tAllocated %llu bytes\tTotal so far %llu\n", i, alloc_size, total);
            alloc_size *= 2;
        }
        else {
            alloc_size /= 2;
        }
    }
    printf("Total alloctions: %llu bytes in %u allocations", total, i);
}
Run Code Online (Sandbox Code Playgroud)

我跑了这个,惊讶于两件事:

  1. 结果不一致.如果我多次运行它,我得不到完全相同的结果.由于虚拟内存模型(或任何它被称为),这不应该是确定性的吗?
  2. 由于程序永远不会释放内存,我希望如果某个大小的malloc失败一次,它不会在以后突然成功,但是 - 惊喜!这是一个程序运行的示例,其他时候我得到了不同(见#1),但结果相似:
42)     Allocated 65536 bytes   Total so far 28337044480
43)     Allocated 16384 bytes   Total so far 28337060864
44)     Allocated 16384 bytes   Total so far 28337077248
45)     Allocated 16384 bytes   Total so far 28337093632
46)     Allocated 16384 bytes   Total so far 28337110016
47)     Allocated 32768 bytes   Total so far 28337142784
48)     Allocated 8192 bytes    Total so far 28337150976
49)     Allocated 8192 bytes    Total so far 28337159168
50)     Allocated 16384 bytes   Total so far 28337175552
51)     Allocated 32768 bytes   Total so far 28337208320
52)     Allocated 65536 bytes   Total so far 28337273856
53)     Allocated 131072 bytes  Total so far 28337404928
54)     Allocated 262144 bytes  Total so far 28337667072
55)     Allocated 16384 bytes   Total so far 28337683456
56)     Allocated 8192 bytes    Total so far 28337691648
57)     Allocated 4096 bytes    Total so far 28337695744
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这是在它已达到峰值分配大小并且正在下降之后.在分配#42和#43之间,它会尝试分配32768个字节并失败.在每个分配#43 - #45之后相同.那怎么突然在#47处理它?你可以在#50 - #54看到同样的事情.这只是一个样本.在此特定运行中,在总共272个分配中多次发生同样的行为.

我希望这不会太长,但我真的很困惑,并且很高兴任何关于此的光明.

编辑
我应该补充说,这是在Win7 64位机器上使用mingw-w64 64位gcc编译器,没有编译器标志

Adr*_*thy 7

在Windows上,如果有足够的页面文件空间来备份,则内存分配(提交)将成功.由于其他进程保留和释放内存的操作,页面文件中可用的空间量可能会发生变化.

在Windows上,malloc是围绕HeapAlloc的瘦包装器,它基于VirtualAlloc构建.

VirtualAlloc允许您保留和/或提交内存.

  • 保留意味着留出一系列进程的虚拟地址空间.如果虚拟地址范围可用,则保留成功.这并不意味着内存可用,只是那些地址不会被用于其他任何地方.

  • 提交意味着在页面文件中留出间距.如果页面文件有足够的可用空间来提交提交,则提交成功.

访问保留但尚未提交的内存是一个错误,可能会崩溃.

访问已提交的内存可能会触发页面错误,系统会通过将这些页面映射到实际RAM来处理这些错误.如果需要,一些RAM将被复制到页面文件(由于提交成功,因此保证有足够的空间),然后该RAM被重新用于最初触发页面错误的访问.因此访问已提交的内存总是成功的.

Windows堆使用VirtualAlloc(及相关功能).在内部,堆以初始保留开始,其中只有一部分被提交.如果出现以下情况,HeapAlloc可能会失败:(1)它耗尽了初始预留或(2)由于页面文件中没有足够的可用空间,因此无法提交更多页面.成功时,HeapAlloc返回指向已提交内存的指针,因此从成功的HeapAlloc访问内存总是成功.

由于malloc只是HeapAlloc的一个薄包装器,前面的段落也适用于malloc.

HeapAlloc分别处理大量分配,这是一个额外的问题.我不确定这些是来自最初的预订还是它们是不同的块.

baruch程序的行为表明它正在进入页面文件中可用内存的限制.页面文件中的可用空间通常随着其他进程的业务而变化,因此,当您接近此限制时,似乎某些分配失败并且其他分配成功也就不足为奇了.

此外,系统可能会根据感知的需求,策略和可用磁盘空间调整页面文件的大小.因此,如果您达到限制一次,但稍后再试,您可能会发现限制更高.