使 calloc 机会化

Make calloc opportunistic

On linux malloc 表现得投机取巧,仅在首次访问时由实内存支持虚拟内存。是否可以修改 calloc 使其也以这种方式运行(在首次访问页面时分配页面并将其归零)?

来自 proc 中的相关 /proc/sys/vm/overcommit_memory 部分:

The amount of memory presently allocated on the system. The committed memory is a sum of all of the memory which has been allocated by processes, even if it has not been "used" by them as of yet. A process which allocates 1GB of memory (using malloc(3) or similar), but only touches 300MB of that memory will only show up as using 300MB of memory even if it has the address space allocated for the entire 1GB. This 1GB is memory which has been "committed" to by the VM and can be used at any time by the allocating application. With strict overcommit enabled on the system (mode 2 /proc/sys/vm/overcommit_memory), allocations which would exceed the CommitLimit (detailed above) will not be permitted. This is useful if one needs to guarantee that processes will not fail due to lack of memory once that memory has been successfully allocated.

虽然没有明说,但我觉得这里的similar就是callocrealloc的意思。所以 calloc 已经表现得像 malloc.

这并不是 malloc() 的特征,使其“投机取巧”。这是内核的一个特性,malloc() 与它无关。

malloc() 每次需要更多内存来满足请求时都会向内核请求一拍内存,而内核每次都说“是的,当然,你有它”,但实际上并没有提供内存。它也是通过提供零内存页来处理后续页面错误的内核。请注意,出于安全考虑,内核提供的任何内存都已清零,因此它同样适用于 malloc()calloc().

也就是说,除非 calloc() 实现通过无条件地将页面本身清零(生成提示内核实际提供内存的页面错误)来破坏这一点,否则它将具有与malloc().


更新:

在我的系统上,以下程序在只有 2 GiB 内存的系统上成功分配了 1 TiB (!):

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

int main() {
    size_t allocationCount = 1024, successfullAllocations = 0;
    char* allocations[allocationCount];
    for(int i = allocationCount; i--; ) {
        if((allocations[i] = calloc(1, 1024*1024*1024))) successfullAllocations++;
    }
    if(successfullAllocations == allocationCount) {
        printf("all %zd allocations were successfull\n", successfullAllocations);
    } else {
        printf("there were %zd failed allocations\n", allocationCount - successfullAllocations);
    }
}

我认为,可以肯定地说,至少我盒子上的 calloc() 实现是“机会主义”的。