diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 6db67f2a98b..8d3f66da0a4 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -103,6 +103,11 @@ "omitted.\n" \ "Example: \"-XX:HiMemReportExec=GC.class_histogram -all;GC.heap_dump\"") \ \ + /* SapMachine 2025-11-24: Configurable limit of malloc arenas */ \ + product(int, GlibcMallocArenas, 0, \ + "Limit glibc malloc arenas, 0 means use OS default, " \ + "1 minimizes memory utilization (our default in later releases)") \ + \ product(bool, UseCpuAllocPath, false, DIAGNOSTIC, \ "Use CPU_ALLOC code path in os::active_processor_count ") \ \ diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 68e824d1059..2c04e26673d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4792,6 +4792,21 @@ jint os::init_2(void) { Linux::fast_thread_clock_init(); + // SapMachine 2025-11-24: + // By default, glibc allocates a new 64 (or 128) MB malloc arena for every + // thread (up to a certain limit which is typically 8 * processor count). + // This is good for few threads which perform a lot of concurrent mallocs, + // but it doesn't fit well to the JVM which has its own memory management + // and rather allocates fewer and larger chunks. + // Using only one arena significantly reduces virtual memory footprint and + // fragmentation. Saving memory seems to be more valuable for the JVM than + // optimizing concurrent mallocs. +#ifdef __GLIBC__ + if (GlibcMallocArenas > 0) { + mallopt(M_ARENA_MAX, GlibcMallocArenas); + } +#endif + if (PosixSignals::init() == JNI_ERR) { return JNI_ERR; }