Doug Lea 分配器的奇怪 malloc 行为

发布于 2024-11-10 05:27:00 字数 2179 浏览 6 评论 0原文

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

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

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

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),我无法分配12 kb:

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

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

I have an very small system with only 16kb of heap, no mmap, no swap. I'm using the latest version 2.8.5 of Doug Lea allocator ftp://g.oswego.edu/pub/misc/malloc-2.8.5.c

UPDATE I made a smaller test case that is easier to understand and see what is my problem

If I allocate 8kb, free it, allocate 12kb, it's working (i != NULL), I can allocate the 12 kb:

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();

displays:

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

If I first allocate a too big buffer (30kb) and then I allocate 8kb, free it, allocate 12kb, it's working (i == NULL), i cannot allocate the 12 kb:

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();

displays:

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

At every moment, only one allocation is made and freed before allocation another block so the memory should never be fragmented.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

-残月青衣踏尘吟 2024-11-17 05:27:00

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

如果尝试延长(或
初始化)连续的 sbrk 段
失败,sysalloc 将空间标记为
不连续,以避免连续
否则会再次失败
破坏从 MORECORE 到
MMAP 可用时。

这会导致后续段不
可合并。目前没有
方法来覆盖此行为。但你
应该能够解决这个问题
删除第 4113-4 行

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

以后我会考虑添加一个
过程中控制这个的方法
其他一些计划支持
页面保护

I had the answer from Doug Lea:

If an attempt to extend (or
initialize) contiguous sbrk's segment
fails, sysalloc marks the space as
non-contiguous, to avoid continual
re-failures which would otherwise
disrupt transitions from MORECORE to
MMAP when availble.

This causes subsequent segments to not
be mergeable. There is currently no
way to override this behavior. But you
should be able to work around it by
removing lines 4113-4

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

In the future, I'll consider adding a
way to control this in the course of
some other planned support for
page-protection

祁梦 2024-11-17 05:27:00

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

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

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

I think this paragraph (from wikipedia, so no guarantees) explains why you are seeing this behaviour:

dlmalloc has a fairly weak free space segment coalescer algorithm, mainly because free space coalescing tends to be extremely slow due to causing TLB cache exhaustion. It is called every (by default) 4096 free() operations and it works by iterating each of the segments previously requested from the system which were not contiguously returned by the system. It tries to identify large ranges of memory which contain no allocated blocks and breaking its segment into two with the free memory being returned to the system. This algorithm works well if dlmalloc is the sole user of the VM system, however if dlmalloc is used simultaneously with another allocator then dlmalloc's free space coalescer can fail to correctly identify opportunities for free memory release.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文