Doug Lea分配器的奇怪malloc行为

Doug Lea分配器的奇怪malloc行为,c,memory-management,malloc,pic,microchip,C,Memory Management,Malloc,Pic,Microchip,我有一个非常小的系统,只有16kb的堆,没有mmap,没有交换。我使用的是Doug Lea分配器的最新版本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(12

我有一个非常小的系统,只有16kb的堆,没有mmap,没有交换。我使用的是Doug Lea分配器的最新版本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();
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: 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
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
如果我先分配一个太大的缓冲区(30kb),然后分配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();
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: 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
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
每时每刻,在分配另一个数据块之前,只进行一次分配并释放一个数据块,因此内存永远不应该被碎片化。

我认为这一段(来自wikipedia,因此没有保证)解释了为什么会出现这种行为:

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

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

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


我从道格·李那里得到了答案:

如果试图扩展(或 初始化)连续sbrk的段 失败,sysalloc将空间标记为 非连续的,以避免连续的 如果不是这样的话,我们将面临失败 中断从MORECORE到 MMAP(当可用时)

这会导致后续段不可用 可以合并。目前没有 重写此行为的方法。但是你 应该能够在 拆卸管路4113-4

将来我会考虑增加一个 在生产过程中如何控制这一点 一些其他计划支持 页面保护


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

如果试图扩展(或 初始化)连续sbrk的段 失败,sysalloc将空间标记为 非连续的,以避免连续的 如果不是这样的话,我们将面临失败 中断从MORECORE到 MMAP(当可用时)

这会导致后续段不可用 可以合并。目前没有 重写此行为的方法。但是你 应该能够在 拆卸管路4113-4

将来我会考虑增加一个 在生产过程中如何控制这一点 一些其他计划支持 页面保护


您正在循环中调用dlstats()-您确定此调用本身不需要堆上的一些内存吗?你在没有调用dlstats的情况下试过吗?@Frank:dlstats不分配内存,我在没有调用它们的情况下试过,我有同样的行为。我把测试用例改成了一个简单的。如果调用malloc导致问题的大小过大,我不明白为什么要在循环中调用dlstats()-你确定这个调用本身不需要堆上的内存吗?你在没有调用dlstats的情况下试过吗?@Frank:dlstats不分配内存,我在没有调用它们的情况下试过,我有同样的行为。我把测试用例改成了一个简单的。如果一个太大的尺寸导致了问题,我想打电话给malloc,我不明白为什么你确定这个信息是最新的?我以为被误导的“优化”被删除了…@R不,一点也不确定。它在维基百科中,描述与他的simptom完全匹配。我更改了测试用例,现在,它不能与合并算法相关。检查新的测试,唯一的区别是,如果我先分配了太大的缓冲区,它就不起作用了。你确定这个信息是最新的吗?我以为被误导的“优化”被删除了…@R不,一点也不确定。它在维基百科中,描述与他的simptom完全匹配。我更改了测试用例,现在,它不能与合并算法相关。检查新的测试,唯一的区别是,如果我首先分配了一个太大的缓冲区,它将不起作用。