mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-05 15:09:31 +03:00
improve fallback code for aligned allocation on Windows
This commit is contained in:
parent
d1db0ffb72
commit
72ab945e28
1 changed files with 32 additions and 36 deletions
66
src/os.c
66
src/os.c
|
@ -67,7 +67,8 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
On windows initializes support for aligned allocation and
|
On windows initializes support for aligned allocation and
|
||||||
large OS pages (if MIMALLOC_LARGE_OS_PAGES is true).
|
large OS pages (if MIMALLOC_LARGE_OS_PAGES is true).
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats);
|
bool _mi_os_decommit(void* addr, size_t size, mi_stats_t* stats);
|
||||||
|
bool _mi_os_commit(void* addr, size_t size, bool* is_zero, mi_stats_t* tld_stats);
|
||||||
|
|
||||||
static void* mi_align_up_ptr(void* p, size_t alignment) {
|
static void* mi_align_up_ptr(void* p, size_t alignment) {
|
||||||
return (void*)_mi_align_up((uintptr_t)p, alignment);
|
return (void*)_mi_align_up((uintptr_t)p, alignment);
|
||||||
|
@ -294,9 +295,23 @@ static bool mi_os_mem_free(void* addr, size_t size, bool was_committed, mi_stats
|
||||||
if (addr == NULL || size == 0) return true; // || _mi_os_is_huge_reserved(addr)
|
if (addr == NULL || size == 0) return true; // || _mi_os_is_huge_reserved(addr)
|
||||||
bool err = false;
|
bool err = false;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
DWORD errcode = 0;
|
||||||
err = (VirtualFree(addr, 0, MEM_RELEASE) == 0);
|
err = (VirtualFree(addr, 0, MEM_RELEASE) == 0);
|
||||||
if (err) {
|
if (err) { errcode = GetLastError(); }
|
||||||
_mi_warning_message("unable to release OS memory: error code 0x%x, addr: %p, size: %zu\n", GetLastError(), addr, size);
|
if (errcode == ERROR_INVALID_ADDRESS) {
|
||||||
|
// In mi_os_mem_alloc_aligned the fallback path may have returned a pointer inside
|
||||||
|
// the memory region returned by VirtualAlloc; in that case we need to free using
|
||||||
|
// the start of the region.
|
||||||
|
MEMORY_BASIC_INFORMATION info = { 0, 0 };
|
||||||
|
VirtualQuery(addr, &info, sizeof(info));
|
||||||
|
if (info.AllocationBase < addr) {
|
||||||
|
errcode = 0;
|
||||||
|
err = (VirtualFree(info.AllocationBase, 0, MEM_RELEASE) == 0);
|
||||||
|
if (err) { errcode = GetLastError(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errcode != 0) {
|
||||||
|
_mi_warning_message("unable to release OS memory: error code 0x%x, addr: %p, size: %zu\n", errcode, addr, size);
|
||||||
}
|
}
|
||||||
#elif defined(MI_USE_SBRK) || defined(__wasi__)
|
#elif defined(MI_USE_SBRK) || defined(__wasi__)
|
||||||
err = false; // sbrk heap cannot be shrunk
|
err = false; // sbrk heap cannot be shrunk
|
||||||
|
@ -731,43 +746,24 @@ static void* mi_os_mem_alloc_aligned(size_t size, size_t alignment, bool commit,
|
||||||
|
|
||||||
// if not aligned, free it, overallocate, and unmap around it
|
// if not aligned, free it, overallocate, and unmap around it
|
||||||
if (((uintptr_t)p % alignment != 0)) {
|
if (((uintptr_t)p % alignment != 0)) {
|
||||||
_mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (%zu bytes, address: %p, commit: %d, is_large: %d)\n", size, p, commit, *is_large);
|
|
||||||
mi_os_mem_free(p, size, commit, stats);
|
mi_os_mem_free(p, size, commit, stats);
|
||||||
|
_mi_warning_message("unable to allocate aligned OS memory directly, fall back to over-allocation (%zu bytes, address: %p, commit: %d, is_large: %d)\n", size, p, commit, *is_large);
|
||||||
if (size >= (SIZE_MAX - alignment)) return NULL; // overflow
|
if (size >= (SIZE_MAX - alignment)) return NULL; // overflow
|
||||||
const size_t over_size = size + alignment;
|
const size_t over_size = size + alignment;
|
||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
// over-allocate and than re-allocate exactly at an aligned address in there.
|
// over-allocate uncommitted (virtual) memory
|
||||||
// this may fail due to threads allocating at the same time so we
|
p = mi_os_mem_alloc(over_size, 0 /*alignment*/, false /* commit? */, false /* allow_large */, is_large, stats);
|
||||||
// retry this at most 3 times before giving up.
|
if (p == NULL) return NULL;
|
||||||
// (we can not decommit around the overallocation on Windows, because we can only
|
|
||||||
// free the original pointer, not one pointing inside the area)
|
// set p to the aligned part in the full region
|
||||||
int flags = MEM_RESERVE;
|
// note: this is dangerous on Windows as VirtualFree needs the actual region pointer
|
||||||
if (commit) flags |= MEM_COMMIT;
|
// but in mi_os_mem_free we handle this (hopefully exceptional) situation.
|
||||||
for (int tries = 0; tries < 3; tries++) {
|
p = mi_align_up_ptr(p, alignment);
|
||||||
// over-allocate to determine a virtual memory range
|
|
||||||
p = mi_os_mem_alloc(over_size, alignment, commit, false, is_large, stats);
|
// explicitly commit only the aligned part
|
||||||
if (p == NULL) return NULL; // error
|
if (commit) {
|
||||||
if (((uintptr_t)p % alignment) == 0) {
|
_mi_os_commit(p, size, NULL, stats);
|
||||||
// if p happens to be aligned, just decommit the left-over area
|
|
||||||
_mi_os_decommit((uint8_t*)p + size, over_size - size, stats);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// otherwise free and allocate at an aligned address in there
|
|
||||||
mi_os_mem_free(p, over_size, commit, stats);
|
|
||||||
void* aligned_p = mi_align_up_ptr(p, alignment);
|
|
||||||
p = mi_win_virtual_alloc(aligned_p, size, alignment, flags, false, allow_large, is_large);
|
|
||||||
if (p != NULL) {
|
|
||||||
_mi_stat_increase(&stats->reserved, size);
|
|
||||||
if (commit) { _mi_stat_increase(&stats->committed, size); }
|
|
||||||
}
|
|
||||||
if (p == aligned_p) break; // success!
|
|
||||||
if (p != NULL) { // should not happen?
|
|
||||||
mi_os_mem_free(p, size, commit, stats);
|
|
||||||
p = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// overallocate...
|
// overallocate...
|
||||||
|
|
Loading…
Add table
Reference in a new issue