为什么我不能释放那些大内存块
Why I cannot free those big memory block
最近在调试程序时遇到了一个奇怪的错误。我们分配一个大缓冲区。释放后,内存并没有回到OS。然后由于内存不足,以下分配可能会失败。然后我做了下面的测试程序。我为指针 c
分配了内存,但没有 free
它来模拟我的真实程序。 (在我的程序中,OpenMPI 调用导致了一个小的内存泄漏。)
由于内存不足,在有 3 GB 可用内存的计算机 (Mac) 上,它会在第 18 行失败。我知道指针 c
会导致内存碎片。但是对于像a
和b
这样的大内存缓冲区,它们是由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);
}
您在评论中提到您正在观察 Mac 下程序的行为。假设您的意思是 OS X,那么您的程序并不像您认为的那样运行。分配器对每个 calloc
调用执行 mmap
调用,并且 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
的三个调用。但是,没有调用 brk
或 sbrk
,也没有调用 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
$
最近在调试程序时遇到了一个奇怪的错误。我们分配一个大缓冲区。释放后,内存并没有回到OS。然后由于内存不足,以下分配可能会失败。然后我做了下面的测试程序。我为指针 c
分配了内存,但没有 free
它来模拟我的真实程序。 (在我的程序中,OpenMPI 调用导致了一个小的内存泄漏。)
由于内存不足,在有 3 GB 可用内存的计算机 (Mac) 上,它会在第 18 行失败。我知道指针 c
会导致内存碎片。但是对于像a
和b
这样的大内存缓冲区,它们是由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);
}
您在评论中提到您正在观察 Mac 下程序的行为。假设您的意思是 OS X,那么您的程序并不像您认为的那样运行。分配器对每个 calloc
调用执行 mmap
调用,并且 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
的三个调用。但是,没有调用 brk
或 sbrk
,也没有调用 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
$