1

我有一个非常小的系统,只有 16kb 的堆,没有 mmap,没有交换。我正在使用 Doug Lea 分配器ftp://g.oswego.edu/pub/misc/malloc-2.8.5.c的最新版本 2.8.5

更新我做了一个更小的测试用例,更容易理解,看看我的问题是什么

如果我分配 8kb,释放它,分配 12kb,它正在工作(i!= NULL),我可以分配 12kb:

char *i;
dlstats();
i = dlmalloc(8192);
printf("DEBUG: %p\n", i);
dlstats();
dlfree(i);
dlstats();
i = dlmalloc(12288);
printf("DEBUG: %p\n", i);
dlstats();
dlfree(i);
dlstats();

显示:

heap 0xa00003f0 sbrk 0xa00003f0 arena 0 ordblks 0 usmblks 0 uordblks 0 fordblks 0 keepcost 0
DEBUG: 0xa00003f8
heap 0xa00003f0 sbrk 0xa0002440 arena 8272 ordblks 1 usmblks 8272 uordblks 8200 fordblks 72 keepcost 32
heap 0xa00003f0 sbrk 0xa0002440 arena 8272 ordblks 1 usmblks 8272 uordblks 0 fordblks 8272 keepcost 8232
DEBUG: 0xa00003f8
heap 0xa00003f0 sbrk 0xa0003460 arena 12400 ordblks 1 usmblks 12400 uordblks 12296 fordblks 104 keepcost 64
heap 0xa00003f0 sbrk 0xa0003460 arena 12400 ordblks 1 usmblks 12400 uordblks 0 fordblks 12400 keepcost 12360

如果我首先分配了一个太大的缓冲区(30kb),然后我分配了 8kb,释放它,分配 12kb,它正在工作(i == NULL),我无法分配 12kb:

char *i;
dlstats();
i = dlmalloc(30000);
printf("DEBUG: %p\n", i);
dlstats();
i = dlmalloc(8192);
printf("DEBUG: %p\n", i);
dlstats();
dlfree(i);
dlstats();
i = dlmalloc(12288);
printf("DEBUG: %p\n", i);
dlstats();
dlfree(i);
dlstats();

显示:

heap 0xa00003f0 sbrk 0xa00003f0 arena 0 ordblks 0 usmblks 0 uordblks 0 fordblks 0 keepcost 0
DEBUG: 0x0
heap 0xa00003f0 sbrk 0xa00003f0 arena 0 ordblks 0 usmblks 0 uordblks 0 fordblks 0 keepcost 0
DEBUG: 0xa00003f8
heap 0xa00003f0 sbrk 0xa0002430 arena 8256 ordblks 1 usmblks 8256 uordblks 8200 fordblks 56 keepcost 16
heap 0xa00003f0 sbrk 0xa0002430 arena 8256 ordblks 1 usmblks 8256 uordblks 0 fordblks 8256 keepcost 8216
DEBUG: 0x0
heap 0xa00003f0 sbrk 0xa0002430 arena 8256 ordblks 1 usmblks 8256 uordblks 0 fordblks 8256 keepcost 8216
heap 0xa00003f0 sbrk 0xa0002430 arena 8256 ordblks 1 usmblks 8256 uordblks 0 fordblks 8256 keepcost 8216

每时每刻,在分配另一个块之前只进行一次分配和释放,因此内存永远不会碎片化。

4

2 回答 2

4

我从 Doug Lea 那里得到了答案:

如果尝试扩展(或初始化)连续 sbrk 的段失败,sysalloc 会将空间标记为非连续,以避免连续重新失败,否则会在可用时中断从 MORECORE 到 MMAP 的转换。

这会导致后续段不可合并。当前无法覆盖此行为。但是您应该可以通过删除第 4113-4 行来解决它

  else
    disable_contiguous(m); /* Don't try contiguous path in the future */

将来,我会考虑在其他计划的页面保护支持过程中添加一种方法来控制这一点

于 2011-05-26T14:21:18.683 回答
1

我认为这一段(来自维基百科,所以不能保证)解释了为什么你会看到这种行为:

dlmalloc 有一个相当弱的空闲空间段合并算法,主要是因为空闲空间合并由于导致 TLB 缓存耗尽而往往非常慢。它被调用每个(默认情况下)4096 free() 操作,它通过迭代以前从系统请求但系统不连续返回的每个段来工作。它尝试识别不包含已分配块的大范围内存,并将其段分成两部分,并将空闲内存返回给系统。如果 dlmalloc 是 VM 系统的唯一用户,则该算法运行良好,但是如果 dlmalloc 与另一个分配器同时使用,则 dlmalloc 的空闲空间合并器可能无法正确识别空闲内存释放的机会。

http://en.wikipedia.org/wiki/Malloc#dlmalloc_and_its_derivatives

于 2011-05-25T11:41:27.067 回答