diff options
| author | Stefan Boberg <[email protected]> | 2026-03-22 10:57:12 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-03-22 10:57:12 +0100 |
| commit | f9e56609401e505c835796726eff35e650810fff (patch) | |
| tree | 1e001f9754e3cd417936a1f2ebfd289db9333975 /src | |
| parent | zen hub command (#877) (diff) | |
| download | zen-f9e56609401e505c835796726eff35e650810fff.tar.xz zen-f9e56609401e505c835796726eff35e650810fff.zip | |
Upgrade mimalloc to v2.2.7 and log active memory allocator (#876)
- Upgrade mimalloc from v2.1.2 to v2.2.7. Note that mimalloc is no longer the default allocator so this only impacts users who somehow opt into mimalloc via `--malloc=mimalloc` or compile with different defaults
- Add all available mimalloc versions (1.6.7–3.2.8) to the package definition for testing
- Log the active memory allocator (with version where available) at server startup
- Annotate vendored rpmalloc with its source commit and version
## Notable changes in mimalloc 2.1.2 → 2.2.7
- **Memory release fix** (2.2.4): fix case where OS memory was not always fully released
- **Race condition fix** (2.2.6): fixed rare race condition and potential buffer overflow in debug statistics
- **Windows arm64 support** (2.1.9)
- **Guarded build** (2.1.9): new build mode that places OS guard pages behind objects to catch buffer overflows
- **THP awareness** (2.2.6): auto-detects transparent huge pages and adjusts purge size to avoid fragmentation
- **Faster TLS access on Windows** (2.2.6)
- **Improved calloc and aligned allocation performance** (2.2.6)
- **New diagnostic APIs** (2.2.2): `mi_options_print`, `mi_arenas_print`, `mi_stat_get` / `mi_stat_get_json`
- **macOS**: use `MADV_FREE_REUSABLE` for better memory behavior (2.2.4)
- **Build fixes**: Android, Xbox, musl, mingw, arm32, Debian 32-bit, non-BMI1 x64 systems
## Allocator logging
Added `FMalloc::GetName()` pure virtual so the server logs which allocator is active at startup:
```
zenserver - memory allocator: mimalloc 2.2.7
```
Allocator names include version where available:
- `mimalloc 2.2.7` (runtime version via `mi_version()`)
- `rpmalloc 1.5.0-dev.20250810` (ad-hoc version from vendored develop branch commit)
- `ansi`, `stomp` (no version info available)
## Test plan
- [x] Builds successfully on Windows (release)
- [x] Verify server startup log shows allocator name
- [x] Test with `--malloc=mimalloc` (default) and `--malloc=rpmalloc`
- [x] Run test suites to check for regressions
Diffstat (limited to 'src')
| -rw-r--r-- | src/zencore/include/zencore/memory/fmalloc.h | 2 | ||||
| -rw-r--r-- | src/zencore/include/zencore/memory/mallocansi.h | 13 | ||||
| -rw-r--r-- | src/zencore/include/zencore/memory/mallocmimalloc.h | 19 | ||||
| -rw-r--r-- | src/zencore/include/zencore/memory/mallocrpmalloc.h | 19 | ||||
| -rw-r--r-- | src/zencore/include/zencore/memory/mallocstomp.h | 3 | ||||
| -rw-r--r-- | src/zencore/memory/fmalloc.cpp | 5 | ||||
| -rw-r--r-- | src/zencore/memory/mallocansi.cpp | 6 | ||||
| -rw-r--r-- | src/zencore/memory/mallocmimalloc.cpp | 12 | ||||
| -rw-r--r-- | src/zencore/memory/mallocrpmalloc.cpp | 5 | ||||
| -rw-r--r-- | src/zencore/memory/mallocstomp.cpp | 6 | ||||
| -rw-r--r-- | src/zencore/memtrack/memorytrace.cpp | 1 | ||||
| -rw-r--r-- | src/zencore/memtrack/tracemalloc.h | 3 | ||||
| -rw-r--r-- | src/zenserver/zenserver.cpp | 3 |
13 files changed, 68 insertions, 29 deletions
diff --git a/src/zencore/include/zencore/memory/fmalloc.h b/src/zencore/include/zencore/memory/fmalloc.h index c50a9729c..8ce4f7acd 100644 --- a/src/zencore/include/zencore/memory/fmalloc.h +++ b/src/zencore/include/zencore/memory/fmalloc.h @@ -151,6 +151,8 @@ public: virtual void Trim(bool bTrimThreadCaches); + virtual const char* GetName() const = 0; + virtual void OutOfMemory(size_t Size, uint32_t Alignment); }; diff --git a/src/zencore/include/zencore/memory/mallocansi.h b/src/zencore/include/zencore/memory/mallocansi.h index 510695c8c..cbc69caed 100644 --- a/src/zencore/include/zencore/memory/mallocansi.h +++ b/src/zencore/include/zencore/memory/mallocansi.h @@ -20,12 +20,13 @@ class FMallocAnsi final : public FMalloc public: FMallocAnsi(); - virtual void* Malloc(size_t Size, uint32_t Alignment) override; - virtual void* TryMalloc(size_t Size, uint32_t Alignment) override; - virtual void* Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; - virtual void* TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; - virtual void Free(void* Ptr) override; - virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; + virtual void* Malloc(size_t Size, uint32_t Alignment) override; + virtual void* TryMalloc(size_t Size, uint32_t Alignment) override; + virtual void* Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; + virtual void* TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; + virtual void Free(void* Ptr) override; + virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; + virtual const char* GetName() const override; }; } // namespace zen diff --git a/src/zencore/include/zencore/memory/mallocmimalloc.h b/src/zencore/include/zencore/memory/mallocmimalloc.h index 759eeb4a6..aa11d51d7 100644 --- a/src/zencore/include/zencore/memory/mallocmimalloc.h +++ b/src/zencore/include/zencore/memory/mallocmimalloc.h @@ -20,15 +20,16 @@ class FMallocMimalloc final : public FMalloc { public: FMallocMimalloc(); - virtual void* Malloc(size_t Size, uint32_t Alignment) override; - virtual void* TryMalloc(size_t Size, uint32_t Alignment) override; - virtual void* Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; - virtual void* TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; - virtual void Free(void* Ptr) override; - virtual void* MallocZeroed(size_t Count, uint32_t Alignment) override; - virtual void* TryMallocZeroed(size_t Count, uint32_t Alignment) override; - virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; - virtual void Trim(bool bTrimThreadCaches) override; + virtual void* Malloc(size_t Size, uint32_t Alignment) override; + virtual void* TryMalloc(size_t Size, uint32_t Alignment) override; + virtual void* Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; + virtual void* TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; + virtual void Free(void* Ptr) override; + virtual void* MallocZeroed(size_t Count, uint32_t Alignment) override; + virtual void* TryMallocZeroed(size_t Count, uint32_t Alignment) override; + virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; + virtual void Trim(bool bTrimThreadCaches) override; + virtual const char* GetName() const override; }; } // namespace zen diff --git a/src/zencore/include/zencore/memory/mallocrpmalloc.h b/src/zencore/include/zencore/memory/mallocrpmalloc.h index be2627b2d..718b7c095 100644 --- a/src/zencore/include/zencore/memory/mallocrpmalloc.h +++ b/src/zencore/include/zencore/memory/mallocrpmalloc.h @@ -21,15 +21,16 @@ class FMallocRpmalloc final : public FMalloc public: FMallocRpmalloc(); ~FMallocRpmalloc(); - virtual void* Malloc(size_t Size, uint32_t Alignment) override; - virtual void* TryMalloc(size_t Size, uint32_t Alignment) override; - virtual void* Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; - virtual void* TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; - virtual void Free(void* Ptr) override; - virtual void* MallocZeroed(size_t Count, uint32_t Alignment) override; - virtual void* TryMallocZeroed(size_t Count, uint32_t Alignment) override; - virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; - virtual void Trim(bool bTrimThreadCaches) override; + virtual void* Malloc(size_t Size, uint32_t Alignment) override; + virtual void* TryMalloc(size_t Size, uint32_t Alignment) override; + virtual void* Realloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; + virtual void* TryRealloc(void* Ptr, size_t NewSize, uint32_t Alignment) override; + virtual void Free(void* Ptr) override; + virtual void* MallocZeroed(size_t Count, uint32_t Alignment) override; + virtual void* TryMallocZeroed(size_t Count, uint32_t Alignment) override; + virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; + virtual void Trim(bool bTrimThreadCaches) override; + virtual const char* GetName() const override; }; } // namespace zen diff --git a/src/zencore/include/zencore/memory/mallocstomp.h b/src/zencore/include/zencore/memory/mallocstomp.h index 5d83868bb..ed0617c95 100644 --- a/src/zencore/include/zencore/memory/mallocstomp.h +++ b/src/zencore/include/zencore/memory/mallocstomp.h @@ -92,7 +92,8 @@ public: * @param SizeOut - If possible, this value is set to the size of the passed in pointer * @return true if succeeded */ - virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; + virtual bool GetAllocationSize(void* Original, size_t& SizeOut) override; + virtual const char* GetName() const override; }; } // namespace zen diff --git a/src/zencore/memory/fmalloc.cpp b/src/zencore/memory/fmalloc.cpp index 3e96003f5..b64fe1f2e 100644 --- a/src/zencore/memory/fmalloc.cpp +++ b/src/zencore/memory/fmalloc.cpp @@ -56,8 +56,9 @@ class FInitialMalloc : public FMalloc Memory::Initialize(); return GMalloc->GetAllocationSize(Original, SizeOut); } - virtual void OnMallocInitialized() override {} - virtual void Trim(bool bTrimThreadCaches) override { ZEN_UNUSED(bTrimThreadCaches); } + virtual void OnMallocInitialized() override {} + virtual void Trim(bool bTrimThreadCaches) override { ZEN_UNUSED(bTrimThreadCaches); } + virtual const char* GetName() const override { return "initial"; } } GInitialMalloc; FMalloc* GMalloc = &GInitialMalloc; /* Memory allocator */ diff --git a/src/zencore/memory/mallocansi.cpp b/src/zencore/memory/mallocansi.cpp index 9c3936172..e9465b46b 100644 --- a/src/zencore/memory/mallocansi.cpp +++ b/src/zencore/memory/mallocansi.cpp @@ -248,4 +248,10 @@ FMallocAnsi::GetAllocationSize(void* Original, size_t& SizeOut) #endif } +const char* +FMallocAnsi::GetName() const +{ + return "ansi"; +} + } // namespace zen diff --git a/src/zencore/memory/mallocmimalloc.cpp b/src/zencore/memory/mallocmimalloc.cpp index 1f9aff404..1679eebde 100644 --- a/src/zencore/memory/mallocmimalloc.cpp +++ b/src/zencore/memory/mallocmimalloc.cpp @@ -191,6 +191,18 @@ FMallocMimalloc::Trim(bool bTrimThreadCaches) mi_collect(bTrimThreadCaches); } +const char* +FMallocMimalloc::GetName() const +{ + static char Name[32] = {}; + if (Name[0] == '\0') + { + int Ver = mi_version(); + snprintf(Name, sizeof(Name), "mimalloc %d.%d.%d", Ver / 100, (Ver / 10) % 10, Ver % 10); + } + return Name; +} + # undef DEBUG_FILL_FREED # undef DEBUG_FILL_NEW diff --git a/src/zencore/memory/mallocrpmalloc.cpp b/src/zencore/memory/mallocrpmalloc.cpp index c45186b77..6c7bfe4f5 100644 --- a/src/zencore/memory/mallocrpmalloc.cpp +++ b/src/zencore/memory/mallocrpmalloc.cpp @@ -186,5 +186,10 @@ FMallocRpmalloc::Trim(bool bTrimThreadCaches) { ZEN_UNUSED(bTrimThreadCaches); } +const char* +FMallocRpmalloc::GetName() const +{ + return "rpmalloc 1.5.0-dev.20250810"; +} } // namespace zen #endif diff --git a/src/zencore/memory/mallocstomp.cpp b/src/zencore/memory/mallocstomp.cpp index db9e1535e..54153cbd4 100644 --- a/src/zencore/memory/mallocstomp.cpp +++ b/src/zencore/memory/mallocstomp.cpp @@ -278,6 +278,12 @@ FMallocStomp::GetAllocationSize(void* Original, size_t& SizeOut) return true; } +const char* +FMallocStomp::GetName() const +{ + return "stomp"; +} + } // namespace zen #endif // WITH_MALLOC_STOMP diff --git a/src/zencore/memtrack/memorytrace.cpp b/src/zencore/memtrack/memorytrace.cpp index 065a6f8ec..13abf7275 100644 --- a/src/zencore/memtrack/memorytrace.cpp +++ b/src/zencore/memtrack/memorytrace.cpp @@ -201,6 +201,7 @@ private: virtual void Free(void* Address) override; virtual bool GetAllocationSize(void* Address, SIZE_T& SizeOut) override { return InnerMalloc->GetAllocationSize(Address, SizeOut); } virtual void OnMallocInitialized() override { InnerMalloc->OnMallocInitialized(); } + virtual const char* GetName() const override { return InnerMalloc->GetName(); } FMalloc* InnerMalloc; }; diff --git a/src/zencore/memtrack/tracemalloc.h b/src/zencore/memtrack/tracemalloc.h index f82d630d7..017962d08 100644 --- a/src/zencore/memtrack/tracemalloc.h +++ b/src/zencore/memtrack/tracemalloc.h @@ -16,7 +16,8 @@ public: virtual void* Realloc(void* Original, size_t Count, uint32_t Alignment) override; virtual void Free(void* Original) override; - virtual void OnMallocInitialized() override { WrappedMalloc->OnMallocInitialized(); } + virtual void OnMallocInitialized() override { WrappedMalloc->OnMallocInitialized(); } + virtual const char* GetName() const override { return WrappedMalloc->GetName(); } FMalloc* WrappedMalloc; }; diff --git a/src/zenserver/zenserver.cpp b/src/zenserver/zenserver.cpp index fe6a5a572..49cbbb9fc 100644 --- a/src/zenserver/zenserver.cpp +++ b/src/zenserver/zenserver.cpp @@ -479,9 +479,9 @@ ZenServerBase::BuildSettingsList(const ZenServerConfig& ServerConfig) {"ContentDir"sv, fmt::format("{}", ServerConfig.ContentDir)}, {"BasePort"sv, fmt::to_string(ServerConfig.BasePort)}, {"CoreLimit"sv, fmt::to_string(ServerConfig.CoreLimit)}, + {"MemoryAllocator"sv, std::string(GMalloc->GetName())}, {"IsDebug"sv, fmt::to_string(ServerConfig.IsDebug)}, {"IsCleanStart"sv, fmt::to_string(ServerConfig.IsCleanStart)}, - {"IsPowerCycle"sv, fmt::to_string(ServerConfig.IsPowerCycle)}, {"IsTest"sv, fmt::to_string(ServerConfig.IsTest)}, {"Detach"sv, fmt::to_string(ServerConfig.Detach)}, {"NoConsoleOutput"sv, fmt::to_string(ServerConfig.LoggingConfig.NoConsoleOutput)}, @@ -739,6 +739,7 @@ ZenServerMain::Run() ZEN_INFO(ZEN_APP_NAME " - using lock file at '{}'", LockFilePath); ZEN_INFO(ZEN_APP_NAME " - starting on port {}, version '{}'", m_ServerOptions.BasePort, ZEN_CFG_VERSION_BUILD_STRING_FULL); + ZEN_INFO(ZEN_APP_NAME " - memory allocator: {}", GMalloc->GetName()); Entry = ServerState.Register(m_ServerOptions.BasePort); |