diff --git a/src/coreclr/src/gc/env/gcenv.os.h b/src/coreclr/src/gc/env/gcenv.os.h index ae398e5503e3b8..a2d837a82d50da 100644 --- a/src/coreclr/src/gc/env/gcenv.os.h +++ b/src/coreclr/src/gc/env/gcenv.os.h @@ -433,20 +433,19 @@ class GCToOSInterface // Remarks: // If a process runs with a restricted memory limit, it returns the limit. If there's no limit // specified, it returns amount of actual physical memory. - // - // PERF TODO: Requires more work to not treat the restricted case to be special. - // To be removed before 3.0 ships. static uint64_t GetPhysicalMemoryLimit(bool* is_restricted=NULL); // Get memory status // Parameters: + // restricted_limit - The amount of physical memory in bytes that the current process is being restricted to. If non-zero, it used to calculate + // memory_load and available_physical. If zero, memory_load and available_physical is calculate based on all available memory. // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory // that is in use (0 indicates no memory use and 100 indicates full memory use). // available_physical - The amount of physical memory currently available, in bytes. // available_page_file - The maximum amount of memory the current process can commit, in bytes. // Remarks: // Any parameter can be null. - static void GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file); + static void GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file); // Get size of an OS memory page static size_t GetPageSize(); diff --git a/src/coreclr/src/gc/gc.cpp b/src/coreclr/src/gc/gc.cpp index a91de0d388d5e0..c09b2c0182f265 100644 --- a/src/coreclr/src/gc/gc.cpp +++ b/src/coreclr/src/gc/gc.cpp @@ -2175,6 +2175,8 @@ uint32_t gc_heap::m_high_memory_load_th; uint32_t gc_heap::v_high_memory_load_th; +bool gc_heap::is_restricted_physical_mem; + uint64_t gc_heap::total_physical_mem = 0; uint64_t gc_heap::entry_available_physical_mem = 0; @@ -19628,7 +19630,7 @@ void gc_heap::get_memory_info (uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { - GCToOSInterface::GetMemoryStatus(memory_load, available_physical, available_page_file); + GCToOSInterface::GetMemoryStatus(is_restricted_physical_mem ? total_physical_mem : 0, memory_load, available_physical, available_page_file); } void fire_mark_event (int heap_num, int root_type, size_t bytes_marked) @@ -34925,11 +34927,14 @@ HRESULT GCHeap::Initialize() g_num_processors = GCToOSInterface::GetTotalProcessorCount(); assert(g_num_processors != 0); - bool is_restricted; gc_heap::total_physical_mem = (size_t)GCConfig::GetGCTotalPhysicalMemory(); - if (!(gc_heap::total_physical_mem)) + if (gc_heap::total_physical_mem != 0) + { + gc_heap::is_restricted_physical_mem = true; + } + else { - gc_heap::total_physical_mem = GCToOSInterface::GetPhysicalMemoryLimit (&is_restricted); + gc_heap::total_physical_mem = GCToOSInterface::GetPhysicalMemoryLimit (&gc_heap::is_restricted_physical_mem); } #ifdef HOST_64BIT @@ -34948,7 +34953,7 @@ HRESULT GCHeap::Initialize() // running in a container, use this limit for the GC heap. if (!(gc_heap::heap_hard_limit)) { - if (is_restricted) + if (gc_heap::is_restricted_physical_mem) { uint64_t physical_mem_for_gc = gc_heap::total_physical_mem * (uint64_t)75 / (uint64_t)100; gc_heap::heap_hard_limit = (size_t)max ((20 * 1024 * 1024), physical_mem_for_gc); diff --git a/src/coreclr/src/gc/gcpriv.h b/src/coreclr/src/gc/gcpriv.h index 3bcb383870773e..e3a6c1f5b60aba 100644 --- a/src/coreclr/src/gc/gcpriv.h +++ b/src/coreclr/src/gc/gcpriv.h @@ -3289,6 +3289,9 @@ class gc_heap PER_HEAP_ISOLATED uint32_t v_high_memory_load_th; + PER_HEAP_ISOLATED + bool is_restricted_physical_mem; + PER_HEAP_ISOLATED uint64_t mem_one_percent; diff --git a/src/coreclr/src/gc/unix/gcenv.unix.cpp b/src/coreclr/src/gc/unix/gcenv.unix.cpp index fd3cd5ec91b6df..9d074231a690de 100644 --- a/src/coreclr/src/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/src/gc/unix/gcenv.unix.cpp @@ -957,7 +957,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount() // Return the size of the user-mode portion of the virtual address space of this process. // Return: -// non zero if it has succeeded, 0 if it has failed +// non zero if it has succeeded, (size_t)-1 if not available size_t GCToOSInterface::GetVirtualMemoryLimit() { #ifdef HOST_64BIT @@ -1143,11 +1143,13 @@ uint64_t GetAvailablePageFile() // Get memory status // Parameters: +// restricted_limit - The amount of physical memory in bytes that the current process is being restricted to. If non-zero, it used to calculate +// memory_load and available_physical. If zero, memory_load and available_physical is calculate based on all available memory. // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory // that is in use (0 indicates no memory use and 100 indicates full memory use). // available_physical - The amount of physical memory currently available, in bytes. // available_page_file - The maximum amount of memory the current process can commit, in bytes. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) +void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { uint64_t available = 0; uint32_t load = 0; @@ -1155,16 +1157,14 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available if (memory_load != nullptr || available_physical != nullptr) { size_t used; - bool isRestricted; - uint64_t total = GetPhysicalMemoryLimit(&isRestricted); - if (isRestricted) + if (restricted_limit != 0) { // Get the physical memory in use - from it, we can get the physical memory available. // We do this only when we have the total physical memory available. if (GetPhysicalMemoryUsed(&used)) { - available = total > used ? total-used : 0; - load = (uint32_t)(((float)used * 100) / (float)total); + available = restricted_limit > used ? restricted_limit - used : 0; + load = (uint32_t)(((float)used * 100) / (float)restricted_limit); } } else @@ -1173,7 +1173,9 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available if (memory_load != NULL) { - uint32_t load = 0; + bool isRestricted; + uint64_t total = GetPhysicalMemoryLimit(&isRestricted); + if (total > available) { used = total - available; @@ -1191,7 +1193,6 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available if (available_page_file != nullptr) *available_page_file = GetAvailablePageFile(); - } // Get a high precision performance counter diff --git a/src/coreclr/src/gc/windows/gcenv.windows.cpp b/src/coreclr/src/gc/windows/gcenv.windows.cpp index 2aaf7ba19aa5e3..a9504bd4b69adf 100644 --- a/src/coreclr/src/gc/windows/gcenv.windows.cpp +++ b/src/coreclr/src/gc/windows/gcenv.windows.cpp @@ -18,22 +18,12 @@ GCSystemInfo g_SystemInfo; -typedef BOOL (WINAPI *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb); -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; - static bool g_SeLockMemoryPrivilegeAcquired = false; static AffinitySet g_processAffinitySet; -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); - namespace { static bool g_fEnableGCNumaAware; @@ -297,36 +287,14 @@ static size_t GetRestrictedPhysicalMemoryLimit() uint64_t total_virtual = 0; uint64_t total_physical = 0; BOOL in_job_p = FALSE; - HINSTANCE hinstKernel32 = 0; - - PIS_PROCESS_IN_JOB GCIsProcessInJob = 0; - PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0; - - hinstKernel32 = LoadLibraryEx(L"kernel32.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); - if (!hinstKernel32) - goto exit; - GCIsProcessInJob = (PIS_PROCESS_IN_JOB)GetProcAddress(hinstKernel32, "IsProcessInJob"); - if (!GCIsProcessInJob) - goto exit; - - if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) + if (!IsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) goto exit; if (in_job_p) { - GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstKernel32, "K32GetProcessMemoryInfo"); - - if (!GCGetProcessMemoryInfo) - goto exit; - - GCQueryInformationJobObject = (PQUERY_INFORMATION_JOB_OBJECT)GetProcAddress(hinstKernel32, "QueryInformationJobObject"); - - if (!GCQueryInformationJobObject) - goto exit; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; - if (GCQueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info, + if (QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info), NULL)) { size_t job_memory_limit = (size_t)UINTPTR_MAX; @@ -373,13 +341,6 @@ static size_t GetRestrictedPhysicalMemoryLimit() if (job_physical_memory_limit == (size_t)UINTPTR_MAX) { job_physical_memory_limit = 0; - - if (hinstKernel32 != 0) - { - FreeLibrary(hinstKernel32); - hinstKernel32 = 0; - GCGetProcessMemoryInfo = 0; - } } // Check to see if we are limited by VM. @@ -399,15 +360,8 @@ static size_t GetRestrictedPhysicalMemoryLimit() 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; + // Limited by virtual address space + job_physical_memory_limit = 0; } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); @@ -1044,7 +998,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount() // Return the size of the user-mode portion of the virtual address space of this process. // Return: -// non zero if it has succeeded, 0 if it has failed +// non zero if it has succeeded, (size_t)-1 if not available size_t GCToOSInterface::GetVirtualMemoryLimit() { MEMORYSTATUSEX memStatus; @@ -1067,7 +1021,7 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) size_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { - if (is_restricted && !g_UseRestrictedVirtualMemory) + if (is_restricted) *is_restricted = true; return restricted_limit; @@ -1081,23 +1035,22 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) // Get memory status // Parameters: +// restricted_limit - The amount of physical memory in bytes that the current process is being restricted to. If non-zero, it used to calculate +// memory_load and available_physical. If zero, memory_load and available_physical is calculate based on all available memory. // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory // that is in use (0 indicates no memory use and 100 indicates full memory use). // available_physical - The amount of physical memory currently available, in bytes. // available_page_file - The maximum amount of memory the current process can commit, in bytes. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) +void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { - uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { size_t workingSetSize; BOOL status = FALSE; - if (!g_UseRestrictedVirtualMemory) - { - PROCESS_MEMORY_COUNTERS pmc; - status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - workingSetSize = pmc.WorkingSetSize; - } + + PROCESS_MEMORY_COUNTERS pmc; + status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + workingSetSize = pmc.WorkingSetSize; if(status) { @@ -1123,9 +1076,10 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available MEMORYSTATUSEX ms; ::GetProcessMemoryLoad(&ms); - if (g_UseRestrictedVirtualMemory) + // 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. + if (ms.ullTotalVirtual < ms.ullTotalPhys) { - _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) diff --git a/src/coreclr/src/vm/gcenv.os.cpp b/src/coreclr/src/vm/gcenv.os.cpp index 6b9e042f04e9b2..e7add3b29e08bb 100644 --- a/src/coreclr/src/vm/gcenv.os.cpp +++ b/src/coreclr/src/vm/gcenv.os.cpp @@ -756,7 +756,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount() // Return the size of the user-mode portion of the virtual address space of this process. // Return: -// non zero if it has succeeded, 0 if it has failed +// non zero if it has succeeded, (size_t)-1 if not available size_t GCToOSInterface::GetVirtualMemoryLimit() { LIMITED_METHOD_CONTRACT; @@ -771,16 +771,6 @@ static size_t g_RestrictedPhysicalMemoryLimit = (size_t)MAX_PTR; #ifndef TARGET_UNIX -// 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 *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb); -static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0; - -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); - static size_t GetRestrictedPhysicalMemoryLimit() { LIMITED_METHOD_CONTRACT; @@ -793,34 +783,14 @@ static size_t GetRestrictedPhysicalMemoryLimit() uint64_t total_virtual = 0; uint64_t total_physical = 0; BOOL in_job_p = FALSE; - HINSTANCE hinstKernel32 = 0; - - PIS_PROCESS_IN_JOB GCIsProcessInJob = 0; - PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0; - - GCIsProcessInJob = &(::IsProcessInJob); - if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) + if (!IsProcessInJob(GetCurrentProcess(), NULL, &in_job_p)) goto exit; if (in_job_p) { - hinstKernel32 = WszLoadLibrary(L"kernel32.dll"); - if (!hinstKernel32) - goto exit; - - GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstKernel32, "K32GetProcessMemoryInfo"); - - if (!GCGetProcessMemoryInfo) - goto exit; - - GCQueryInformationJobObject = &(::QueryInformationJobObject); - - if (!GCQueryInformationJobObject) - goto exit; - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info; - if (GCQueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info, + if (QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &limit_info, sizeof(limit_info), NULL)) { size_t job_memory_limit = (size_t)MAX_PTR; @@ -867,13 +837,6 @@ static size_t GetRestrictedPhysicalMemoryLimit() if (job_physical_memory_limit == (size_t)MAX_PTR) { job_physical_memory_limit = 0; - - if (hinstKernel32 != 0) - { - FreeLibrary(hinstKernel32); - hinstKernel32 = 0; - GCGetProcessMemoryInfo = 0; - } } // Check to see if we are limited by VM. @@ -893,15 +856,8 @@ static size_t GetRestrictedPhysicalMemoryLimit() 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; + // Limited by virtual address space + job_physical_memory_limit = 0; } VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit); @@ -928,9 +884,6 @@ static size_t GetRestrictedPhysicalMemoryLimit() // Get the physical memory that this process can use. // Return: // non zero if it has succeeded, 0 if it has failed -// -// PERF TODO: Requires more work to not treat the restricted case to be special. -// To be removed before 3.0 ships. uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) { LIMITED_METHOD_CONTRACT; @@ -941,11 +894,7 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) size_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { - if (is_restricted -#ifndef TARGET_UNIX - && !g_UseRestrictedVirtualMemory -#endif - ) + if (is_restricted) *is_restricted = true; return restricted_limit; @@ -965,26 +914,22 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) // available_page_file - The maximum amount of memory the current process can commit, in bytes. // Remarks: // Any parameter can be null. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) +void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) { LIMITED_METHOD_CONTRACT; - uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit(); if (restricted_limit != 0) { size_t workingSetSize; BOOL status = FALSE; #ifndef TARGET_UNIX - if (!g_UseRestrictedVirtualMemory) - { - PROCESS_MEMORY_COUNTERS pmc; - status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); - workingSetSize = pmc.WorkingSetSize; - } + PROCESS_MEMORY_COUNTERS pmc; + status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)); + workingSetSize = pmc.WorkingSetSize; #else status = PAL_GetPhysicalMemoryUsed(&workingSetSize); #endif - if(status) + if (status) { if (memory_load) *memory_load = (uint32_t)((float)workingSetSize * 100.0 / (float)restricted_limit); @@ -1009,9 +954,10 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available GetProcessMemoryLoad(&ms); #ifndef TARGET_UNIX - if (g_UseRestrictedVirtualMemory) + // 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. + if (ms.ullTotalVirtual < ms.ullTotalPhys) { - _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)