You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Arena allocator pre-maturely returns NOMEM on parent arena while space is still available in child arena #1403
Looks like when registering a very large arena, mimalloc internally split it into smaller sub-arenas (16 GiB each) with parent-children relationship. Then if a series of allocation exhausted the parent arena, the mimalloc API would pre-maturely return NOMEM even though there are still space in the child arenas. This looks like a bug in the macro to iterate over the sub-arenas in the arena.c code.
Repro (version: v3)
#include<mimalloc.h>#include<stdint.h>#include<stdio.h>#include<sys/mman.h>#defineGIB ((size_t)1024 * 1024 * 1024)
#defineMIB ((size_t)1024 * 1024)
intmain(void) {
constsize_tarena_size=24*GIB;
constsize_tallocation_size=64*MIB;
constsize_tallocation_count=272; // 17 GiB: requires a child arena.constsize_talignment=mi_arena_min_alignment();
constsize_tmapping_size=arena_size+alignment;
void*mapping=mmap(NULL, mapping_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
if (mapping==MAP_FAILED) {
perror("mmap");
return1;
}
constuintptr_taligned=
((uintptr_t)mapping+alignment-1) & ~((uintptr_t)alignment-1);
mi_arena_id_tarena_id=NULL;
if (!mi_manage_os_memory_ex((void*)aligned, arena_size,
true, /* committed */
false, /* pinned */
true, /* initially zero */-1, /* no NUMA preference */
true, /* exclusive */&arena_id)) {
fprintf(stderr, "failed to register the 24 GiB arena\n");
return1;
}
mi_heap_t*heap=mi_heap_new_in_arena(arena_id);
if (heap==NULL) {
fprintf(stderr, "failed to create the arena heap\n");
return1;
}
for (size_ti=0; i<allocation_count; i++) {
void*p=mi_heap_malloc(heap, allocation_size);
if (p==NULL) {
fprintf(stderr,
"allocation %zu failed after %zu MiB; child arena was not used\n",
i, i*allocation_size / MIB);
return1;
}
if (!mi_arena_contains(arena_id, p)) {
fprintf(stderr, "allocation %zu came from outside the requested arena\n", i);
return1;
}
}
printf("allocated %zu MiB from the parent arena and its children\n",
allocation_count*allocation_size / MIB);
return0;
}
Activity