为什么我无法释放那些大内存块

时间:2015-05-07 16:07:51

标签: c unix memory memory-management

最近,我在调试程序时遇到了一个奇怪的错误。我们分配一个大缓冲区。释放后,内存没有返回操作系统。然后由于内存不足,以下分配可能会失败。然后我做了以下测试程序。我为指针c分配了内存,并没有free来模拟我的真实程序。 (在我的程序中,OpenMPI调用导致内存泄漏很少。)

由于内存不足,计算机(Mac)上的第18行会因3 GB可用内存而失败。我知道指针c会导致内存碎片。但对于像ab这样的大内存缓冲区,它们由mmap分配,而不是brk。它们应该可以直接释放,对吧?我该怎么做才能解决这个问题?

#include <stdlib.h>
#include <string.h>

int main(){

    float *a=malloc(1250000000);
    memset(a, (char)1, 1250000000);

    float *b=malloc(1250000000);
    memset(b, (char)1, 1250000000);

    float *c=malloc(10);
    memset(c, (char)1, 10);

    free(b);
    free(a);

    float *d=malloc(2000000000);  /* FAILS HERE */
    memset(d, (char)1, 2000000000);
}

1 个答案:

答案 0 :(得分:2)

您在评论中提到您正在观察Mac下程序的行为。假设您的意思是操作系统X,那么您的程序的行为并不像您认为的那样。分配器对每个mmap调用执行calloc次调用,free调用不会导致munmap,因为分配器预计会重用您分配的内存。

可以使用dtruss

来验证
$ dtruss -f -t mmap ./a.out 
    PID/THRD  SYSCALL(args)          = return
57843/0x16bf38:  mmap(0x10C119000, 0x2000, 0x5, 0x12, 0x3, 0x1000)       = 0x10C119000 0
57843/0x16bf38:  mmap(0x10C11B000, 0x1000, 0x3, 0x12, 0x3, 0x3000)       = 0x10C11B000 0
57843/0x16bf38:  mmap(0x10C11C000, 0x1FC0, 0x1, 0x12, 0x3, 0x4000)       = 0x10C11C000 0

$

注意对mmap的三次调用。但是,无法拨打brksbrk,也不会拨打munmap

$ dtruss -f -t brk ./a.out 
    PID/THRD  SYSCALL(args)          = return

$ dtruss -f -t sbrk ./a.out 
    PID/THRD  SYSCALL(args)          = return

$ dtruss -f -t munmap ./a.out 
    PID/THRD  SYSCALL(args)          = return

$