diff --git a/src/os.c b/src/os.c index 510d0dfc..500229f9 100644 --- a/src/os.c +++ b/src/os.c @@ -180,7 +180,7 @@ static bool mi_os_mem_free(void* addr, size_t size, mi_stats_t* stats) static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment, DWORD flags) { #if defined(MEM_EXTENDED_PARAMETER_TYPE_BITS) if (try_alignment > 0 && (try_alignment % _mi_os_page_size()) == 0 && pVirtualAlloc2 != NULL) { - // on modern Windows try use VirtualAlloc2 + // on modern Windows try use VirtualAlloc2 for aligned allocation MEM_ADDRESS_REQUIREMENTS reqs = { 0 }; reqs.Alignment = try_alignment; MEM_EXTENDED_PARAMETER param = { 0 }; @@ -193,10 +193,22 @@ static void* mi_win_virtual_allocx(void* addr, size_t size, size_t try_alignment } static void* mi_win_virtual_alloc(void* addr, size_t size, size_t try_alignment, DWORD flags) { + static size_t large_page_try_ok = 0; void* p = NULL; if (use_large_os_page(size, try_alignment)) { - p = mi_win_virtual_allocx(addr, size, try_alignment, MEM_LARGE_PAGES | flags); - // fall back to non-large page allocation on error (`p == NULL`). + if (large_page_try_ok > 0) { + // if a large page page allocation fails, it seems the calls to VirtualAlloc get very expensive. + // therefore, once a large page allocation failed, we don't try again for `large_page_try_ok` times. + large_page_try_ok--; + } + else { + // large OS pages must always reserve and commit. + p = mi_win_virtual_allocx(addr, size, try_alignment, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE | flags); + // fall back to non-large page allocation on error (`p == NULL`). + if (p == NULL) { + large_page_try_ok = 10; // on error, don't try again for the next N allocations + } + } } if (p == NULL) { p = mi_win_virtual_allocx(addr, size, try_alignment, flags);