diff options
author | Maoni Stephens <Maoni0@users.noreply.github.com> | 2018-03-27 13:04:26 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-27 13:04:26 -0700 |
commit | ef88a92215a8f90fe0bd8b0327c16bb889902105 (patch) | |
tree | bc661a38c1c6a58a0157f0d85fd13e3977346424 /src/gc | |
parent | dff4f7181595e9d4a2dd76971a4465cb8db0eb58 (diff) | |
download | coreclr-ef88a92215a8f90fe0bd8b0327c16bb889902105.tar.gz coreclr-ef88a92215a8f90fe0bd8b0327c16bb889902105.tar.bz2 coreclr-ef88a92215a8f90fe0bd8b0327c16bb889902105.zip |
restrict memory limit by taking VM into consideration (#17177)
Diffstat (limited to 'src/gc')
-rw-r--r-- | src/gc/windows/gcenv.windows.cpp | 102 |
1 files changed, 83 insertions, 19 deletions
diff --git a/src/gc/windows/gcenv.windows.cpp b/src/gc/windows/gcenv.windows.cpp index e258834abc..85bcd851a7 100644 --- a/src/gc/windows/gcenv.windows.cpp +++ b/src/gc/windows/gcenv.windows.cpp @@ -21,6 +21,10 @@ static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0; static size_t g_RestrictedPhysicalMemoryLimit = (size_t)UINTPTR_MAX; +// For 32-bit processes the virtual address range could be smaller than the amount of physical +// memory on the machine/in the container, we need to restrict by the VM. +static bool g_UseRestrictedVirtualMemory = false; + typedef BOOL (WINAPI *PIS_PROCESS_IN_JOB)(HANDLE processHandle, HANDLE jobHandle, BOOL* result); typedef BOOL (WINAPI *PQUERY_INFORMATION_JOB_OBJECT)(HANDLE jobHandle, JOBOBJECTINFOCLASS jobObjectInfoClass, void* lpJobObjectInfo, DWORD cbJobObjectInfoLength, LPDWORD lpReturnLength); @@ -31,13 +35,6 @@ void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX) pMSEX->dwLength = sizeof(MEMORYSTATUSEX); BOOL fRet = ::GlobalMemoryStatusEx(pMSEX); assert(fRet); - - // If the machine has more RAM than virtual address limit, let us cap it. - // Our GC can never use more than virtual address limit. - if (pMSEX->ullAvailPhys > pMSEX->ullTotalVirtual) - { - pMSEX->ullAvailPhys = pMSEX->ullAvailVirtual; - } } static size_t GetRestrictedPhysicalMemoryLimit() @@ -49,6 +46,8 @@ static size_t GetRestrictedPhysicalMemoryLimit() return g_RestrictedPhysicalMemoryLimit; size_t job_physical_memory_limit = (size_t)UINTPTR_MAX; + uint64_t total_virtual = 0; + uint64_t total_physical = 0; BOOL in_job_p = FALSE; HINSTANCE hinstKernel32 = 0; @@ -109,6 +108,8 @@ static size_t GetRestrictedPhysicalMemoryLimit() MEMORYSTATUSEX ms; ::GetProcessMemoryLoad(&ms); + total_virtual = ms.ullTotalVirtual; + total_physical = ms.ullAvailPhys; // A sanity check in case someone set a larger limit than there is actual physical memory. job_physical_memory_limit = (size_t) min (job_physical_memory_limit, ms.ullTotalPhys); @@ -120,7 +121,40 @@ exit: { job_physical_memory_limit = 0; - FreeLibrary(hinstKernel32); + if (hinstKernel32 != 0) + { + FreeLibrary(hinstKernel32); + hinstKernel32 = 0; + GCGetProcessMemoryInfo = 0; + } + } + + // Check to see if we are limited by VM. + if (total_virtual == 0) + { + MEMORYSTATUSEX ms; + ::GetProcessMemoryLoad(&ms); + + total_virtual = ms.ullTotalVirtual; + total_physical = ms.ullTotalPhys; + } + + if (job_physical_memory_limit != 0) + { + total_physical = job_physical_memory_limit; + } + + if (total_virtual < total_physical) + { + if (hinstKernel32 != 0) + { + // We can also free the lib here - if we are limited by VM we will not be calling + // GetProcessMemoryInfo. + FreeLibrary(hinstKernel32); + GCGetProcessMemoryInfo = 0; + } + g_UseRestrictedVirtualMemory = true; + job_physical_memory_limit = (size_t)total_virtual; } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); @@ -495,13 +529,26 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { - PROCESS_MEMORY_COUNTERS pmc; - if (GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) + size_t workingSetSize; + BOOL status = FALSE; + if (!g_UseRestrictedVirtualMemory) + { + PROCESS_MEMORY_COUNTERS pmc; + status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + workingSetSize = pmc.WorkingSetSize; + } + + if(status) { if (memory_load) - *memory_load = (uint32_t)((float)pmc.WorkingSetSize * 100.0 / (float)restricted_limit); + *memory_load = (uint32_t)((float)workingSetSize * 100.0 / (float)restricted_limit); if (available_physical) - *available_physical = restricted_limit - pmc.WorkingSetSize; + { + if(workingSetSize > restricted_limit) + *available_physical = 0; + else + *available_physical = restricted_limit - workingSetSize; + } // Available page file doesn't mean much when physical memory is restricted since // we don't know how much of it is available to this process so we are not going to // bother to make another OS call for it. @@ -514,13 +561,30 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available MEMORYSTATUSEX ms; ::GetProcessMemoryLoad(&ms); - - if (memory_load != nullptr) - *memory_load = ms.dwMemoryLoad; - if (available_physical != nullptr) - *available_physical = ms.ullAvailPhys; - if (available_page_file != nullptr) - *available_page_file = ms.ullAvailPageFile; + + if (g_UseRestrictedVirtualMemory) + { + _ASSERTE (ms.ullTotalVirtual == restricted_limit); + if (memory_load != NULL) + *memory_load = (uint32_t)((float)(ms.ullTotalVirtual - ms.ullAvailVirtual) * 100.0 / (float)ms.ullTotalVirtual); + if (available_physical != NULL) + *available_physical = ms.ullTotalVirtual; + + // Available page file isn't helpful when we are restricted by virtual memory + // since the amount of memory we can reserve is less than the amount of + // memory we can commit. + if (available_page_file != NULL) + *available_page_file = 0; + } + else + { + if (memory_load != NULL) + *memory_load = ms.dwMemoryLoad; + if (available_physical != NULL) + *available_physical = ms.ullAvailPhys; + if (available_page_file != NULL) + *available_page_file = ms.ullAvailPageFile; + } } // Get a high precision performance counter |