From 1e6e939cb1cddbb59edcc388ceae68ee06f01809 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 3 Sep 2025 15:22:20 +0200 Subject: [PATCH 1/3] Limit doublemapper maximum size The double mapping currently sets the maximum size of the double mapped memory to 2TB. However, that causes the runtime to fail to start if there is a rlimit for max file size set to a smaller value. This change fixed the problem by clipping the max double mapped memory size by that rlimit and also uses much more conservative size even without the file size limit set. It is now set to the total amount of physical memory by default and also clipped by the virtual memory rlimit. Close #117819 --- src/coreclr/minipal/Unix/doublemapping.cpp | 37 ++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index 47a91c6243d9c0..8f6c81d800e095 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #if defined(TARGET_LINUX) && !defined(MFD_CLOEXEC) #include #include // __NR_memfd_create @@ -81,14 +82,46 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu return false; } #endif + off_t maxDoubleMappedMemorySize = MaxDoubleMappedSize; + + // Set the maximum double mapped memory size to the size of the physical memory + long pages = sysconf(_SC_PHYS_PAGES); + if (pages != -1) + { + long pageSize = sysconf(_SC_PAGE_SIZE); + if (pageSize != -1) + { + maxDoubleMappedMemorySize = (off_t)pages * pageSize; + } + } + + // Clip the maximum double mapped memory size to the virtual address space limit + struct rlimit virtualAddressSpaceLimit; + if (getrlimit(RLIMIT_AS, &virtualAddressSpaceLimit) == 0) + { + if (maxDoubleMappedMemorySize > virtualAddressSpaceLimit.rlim_cur) + { + maxDoubleMappedMemorySize = virtualAddressSpaceLimit.rlim_cur; + } + } + + // Clip the maximum double mapped memory size to the file size limit + struct rlimit fileSizeLimit; + if (getrlimit(RLIMIT_FSIZE, &fileSizeLimit) == 0) + { + if (maxDoubleMappedMemorySize > fileSizeLimit.rlim_cur) + { + maxDoubleMappedMemorySize = fileSizeLimit.rlim_cur; + } + } - if (ftruncate(fd, MaxDoubleMappedSize) == -1) + if (ftruncate(fd, maxDoubleMappedMemorySize) == -1) { close(fd); return false; } - *pMaxExecutableCodeSize = MaxDoubleMappedSize; + *pMaxExecutableCodeSize = maxDoubleMappedMemorySize; *pHandle = (void*)(size_t)fd; #else // !TARGET_APPLE From 239d1185a10be4f03b6ef745f7e883e923755012 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 3 Sep 2025 17:29:53 +0200 Subject: [PATCH 2/3] In case of VM limit, use just 1/4 of the space --- src/coreclr/minipal/Unix/doublemapping.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index 8f6c81d800e095..214d1ab0b8d9d4 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -91,14 +91,21 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu long pageSize = sysconf(_SC_PAGE_SIZE); if (pageSize != -1) { - maxDoubleMappedMemorySize = (off_t)pages * pageSize; + long physicalMemorySize = (long)pages * pageSize; + if (maxDoubleMappedMemorySize > physicalMemorySize) + { + maxDoubleMappedMemorySize = physicalMemorySize; + } } } - // Clip the maximum double mapped memory size to the virtual address space limit + // Clip the maximum double mapped memory size to 1/4 of the virtual address space limit. + // When such a limit is set, GC reserves 1/2 of it, so we need to leave something + // for the rest of the process. struct rlimit virtualAddressSpaceLimit; - if (getrlimit(RLIMIT_AS, &virtualAddressSpaceLimit) == 0) + if ((getrlimit(RLIMIT_AS, &virtualAddressSpaceLimit) == 0) && (virtualAddressSpaceLimit.rlim_cur != RLIM_INFINITY)) { + virtualAddressSpaceLimit.rlim_cur /= 4; if (maxDoubleMappedMemorySize > virtualAddressSpaceLimit.rlim_cur) { maxDoubleMappedMemorySize = virtualAddressSpaceLimit.rlim_cur; @@ -107,7 +114,7 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu // Clip the maximum double mapped memory size to the file size limit struct rlimit fileSizeLimit; - if (getrlimit(RLIMIT_FSIZE, &fileSizeLimit) == 0) + if ((getrlimit(RLIMIT_FSIZE, &fileSizeLimit) == 0) && (fileSizeLimit.rlim_cur != RLIM_INFINITY)) { if (maxDoubleMappedMemorySize > fileSizeLimit.rlim_cur) { From b73de3cdfb9b5fcaf9f6b65da09c7e49bf3d2715 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Thu, 4 Sep 2025 13:53:40 +0200 Subject: [PATCH 3/3] Change physicalMemorySize to 64 bits Even on 32 bit targets, more than 4GB memory may be available. --- src/coreclr/minipal/Unix/doublemapping.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/minipal/Unix/doublemapping.cpp b/src/coreclr/minipal/Unix/doublemapping.cpp index 214d1ab0b8d9d4..205a2cac789fae 100644 --- a/src/coreclr/minipal/Unix/doublemapping.cpp +++ b/src/coreclr/minipal/Unix/doublemapping.cpp @@ -82,7 +82,7 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu return false; } #endif - off_t maxDoubleMappedMemorySize = MaxDoubleMappedSize; + uint64_t maxDoubleMappedMemorySize = MaxDoubleMappedSize; // Set the maximum double mapped memory size to the size of the physical memory long pages = sysconf(_SC_PHYS_PAGES); @@ -91,7 +91,7 @@ bool VMToOSInterface::CreateDoubleMemoryMapper(void** pHandle, size_t *pMaxExecu long pageSize = sysconf(_SC_PAGE_SIZE); if (pageSize != -1) { - long physicalMemorySize = (long)pages * pageSize; + uint64_t physicalMemorySize = (uint64_t)pages * pageSize; if (maxDoubleMappedMemorySize > physicalMemorySize) { maxDoubleMappedMemorySize = physicalMemorySize;