aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-22 10:57:12 +0100
committerGitHub Enterprise <[email protected]>2026-03-22 10:57:12 +0100
commitf9e56609401e505c835796726eff35e650810fff (patch)
tree1e001f9754e3cd417936a1f2ebfd289db9333975
parentzen hub command (#877) (diff)
downloadzen-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
-rw-r--r--repo/packages/m/mimalloc/xmake.lua26
-rw-r--r--src/zencore/include/zencore/memory/fmalloc.h2
-rw-r--r--src/zencore/include/zencore/memory/mallocansi.h13
-rw-r--r--src/zencore/include/zencore/memory/mallocmimalloc.h19
-rw-r--r--src/zencore/include/zencore/memory/mallocrpmalloc.h19
-rw-r--r--src/zencore/include/zencore/memory/mallocstomp.h3
-rw-r--r--src/zencore/memory/fmalloc.cpp5
-rw-r--r--src/zencore/memory/mallocansi.cpp6
-rw-r--r--src/zencore/memory/mallocmimalloc.cpp12
-rw-r--r--src/zencore/memory/mallocrpmalloc.cpp5
-rw-r--r--src/zencore/memory/mallocstomp.cpp6
-rw-r--r--src/zencore/memtrack/memorytrace.cpp1
-rw-r--r--src/zencore/memtrack/tracemalloc.h3
-rw-r--r--src/zenserver/zenserver.cpp3
-rw-r--r--thirdparty/xmake.lua3
-rw-r--r--xmake.lua2
16 files changed, 98 insertions, 30 deletions
diff --git a/repo/packages/m/mimalloc/xmake.lua b/repo/packages/m/mimalloc/xmake.lua
index 54d6613b8..49492542f 100644
--- a/repo/packages/m/mimalloc/xmake.lua
+++ b/repo/packages/m/mimalloc/xmake.lua
@@ -5,6 +5,32 @@ package("mimalloc")
set_license("MIT")
set_urls("https://github.com/microsoft/mimalloc/archive/v$(version).zip")
+ add_versions("3.2.8", "63302742e911c8724c2bcc192aea51fc8921c7916ca8a68b037280d72126dfb5")
+ add_versions("3.2.7", "0200e80d51e18bab4776a0aaf74b99fcb16e106b816fd5dbde545c71cfc90e10")
+ add_versions("3.2.6", "320e9b91ea2f18536129633f01eff81de3e6ee40b07e519a70382b80aaef5ea6")
+ add_versions("3.1.6", "bedddb34e47447dde3aa7ddb5a1e2ec5d049f30449b3d97a3519e430df55d387")
+ add_versions("3.1.5", "3cf724ec469198f23505d157893331f9d062e982c38b2c92a7fb789d7ddb67d9")
+ add_versions("3.1.4", "fd6d79ed105c275f884e41fd7d2282377f9fe61591e7038024ab2c528f2b2d5f")
+ add_versions("3.0.12", "bebd1fc10b6c20398d578fc9d00d9f14716868668a4809187a51e66868596655")
+ add_versions("3.0.11", "32c067fad24285e5c8c0cceb7108f841b5902227e0314b285146cd1cc7092926")
+ add_versions("3.0.10", "a2b6925f83c536a287ef1ed2b9337377ea7dec6868a4e8b90509985d43cfb2f5")
+ add_versions("3.0.9", "fb5b9a6bc070bad1a96bea3ae77477d8ee7648f8ffb7cd7a3795de159a9718a6")
+ add_versions("3.0.8", "fcde151d6bb773b0b64af23c6199fe20ec45550c0bff39ffda80c623959d1788")
+ add_versions("3.0.7", "a4756650ef5807db912b6630dcb56831bf08bb23487a2168b176f989e7f35afd")
+ add_versions("3.0.3", "08a917e331164cd77052377f1e6d86de7febc8663dc117648319e662c0d4e6a4")
+ add_versions("3.0.1", "cf19cd180c1768b9ef9ee18e8ba8551f1992ec1b7c71f15344e42a62b0e0a338")
+
+ add_versions("2.2.7", "bf59bd7166cc56fc102107360404ad3add35014ed0a2505e4e36f269ea3e3418")
+ add_versions("2.2.6", "60935f5a7fcb2bc84517c6efa5644dcc4b7e8ab48573bc9eac86034e2593ff06")
+ add_versions("2.2.4", "664667a48c9f101d979bbe4e41ee631da49d2024e30d66b7779b6ba4279af367")
+ add_versions("2.2.3", "35fa4a4c094bb97571378192f82b78d65b6322ad7f3c6b0ad272058fa829d28c")
+ add_versions("2.2.2", "76878acd96650ae1343ec66373cc1b4ebe8523175560226f5291b73a4e575f94")
+ add_versions("2.1.9", "efc9531e88bf64403dd4955131ad5d0d24c0ff63be6561344dff77e1bcebcc78")
+ add_versions("2.1.8", "538b63ba0d43c184cfaac9ffef10455ae809c3560a59750dc667fc62e784c0d5")
+ add_versions("2.1.7", "fa61cf01e3dd869b35275bfd8be95bfde77f0b65dfa7e34012c09a66e1ea463f")
+ add_versions("2.1.6", "a1a775563e90b447569191c2c060b81f9a771e6d5f857adc17a7e9eb9d5c1215")
+ add_versions("2.1.5", "7f013cc4f848fe19d146629c2fc94c9e82119eddc85ee2c032bcb003361654f0")
+ add_versions("2.1.4", "41aa2f6ca7d60b41d0ed1644a4ab437a2233ca40115e36b41a1ebe07b7d58854")
add_versions("2.1.2", "86281c918921c1007945a8a31e5ad6ae9af77e510abfec20d000dd05d15123c7")
add_versions("2.0.7", "ddb32937aabddedd0d3a57bf68158d4e53ecf9e051618df3331a67182b8b0508")
add_versions("2.0.6", "23e7443d0b4d7aa945779ea8a806e4e109c0ed62d740953d3656cddea7e04cf8")
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);
diff --git a/thirdparty/xmake.lua b/thirdparty/xmake.lua
index 196f184ae..21a98c967 100644
--- a/thirdparty/xmake.lua
+++ b/thirdparty/xmake.lua
@@ -32,6 +32,9 @@ target('ue-trace')
add_includedirs("trace", {public=true})
add_headerfiles("trace/**.h")
+-- rpmalloc 1.5.0-dev.20250810
+-- Vendored from develop branch commit 6b34d956911b (2025-08-10)
+-- https://github.com/mjansson/rpmalloc/commit/6b34d956911b
target('rpmalloc')
set_kind("static")
set_group('thirdparty')
diff --git a/xmake.lua b/xmake.lua
index 1f57ddf97..54802f3f3 100644
--- a/xmake.lua
+++ b/xmake.lua
@@ -224,7 +224,7 @@ add_requires("nomad", {system = false}) -- for nomad provisioner tests
add_requires("oidctoken", {system = false})
if has_config("zenmimalloc") and not use_asan then
- add_requires("mimalloc", {system = false})
+ add_requires("mimalloc 2.2.7", {system = false})
end
--------------------------------------------------------------------------