diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 160969df454..82e048aae23 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -245,6 +245,10 @@ static bool is_close_to_brk(address a) { return false; } +julong os::free_memory() { + return Aix::available_memory(); +} + julong os::available_memory() { return Aix::available_memory(); } diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index d4af6a6d606..ecd181f8989 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -59,6 +59,7 @@ class os::Aix { static int _extshm; static julong available_memory(); + static julong free_memory(); static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 2079867bbb5..3ae932f312d 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -138,6 +138,10 @@ julong os::available_memory() { return Bsd::available_memory(); } +julong os::free_memory() { + return Bsd::available_memory(); +} + // available here means free julong os::Bsd::available_memory() { uint64_t available = physical_memory() >> 2; diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp index 87f4b69587f..d34803e144b 100644 --- a/src/hotspot/os/bsd/os_bsd.hpp +++ b/src/hotspot/os/bsd/os_bsd.hpp @@ -46,6 +46,7 @@ class os::Bsd { static pthread_t _main_thread; static julong available_memory(); + static julong free_memory(); static julong physical_memory() { return _physical_memory; } static void initialize_system_info(); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 7bb99874848..2313f371db9 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -216,15 +216,8 @@ static bool suppress_primordial_thread_resolution = false; // utility functions -julong os::available_memory() { - return Linux::available_memory(); -} - -julong os::Linux::available_memory() { - // values in struct sysinfo are "unsigned long" - struct sysinfo si; - julong avail_mem; - +julong os::Linux::available_memory_in_container() { + julong avail_mem = static_cast(-1L); if (OSContainer::is_containerized()) { jlong mem_limit = OSContainer::memory_limit_in_bytes(); jlong mem_usage; @@ -233,15 +226,57 @@ julong os::Linux::available_memory() { } if (mem_limit > 0 && mem_usage > 0) { avail_mem = mem_limit > mem_usage ? (julong)mem_limit - (julong)mem_usage : 0; - log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); - return avail_mem; } } + return avail_mem; +} + +julong os::available_memory() { + return Linux::available_memory(); +} + +julong os::Linux::available_memory() { + julong avail_mem = available_memory_in_container(); + if (avail_mem != static_cast(-1L)) { + log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem); + return avail_mem; + } + + FILE *fp = os::fopen("/proc/meminfo", "r"); + if (fp != nullptr) { + char buf[80]; + do { + if (fscanf(fp, "MemAvailable: " JULONG_FORMAT " kB", &avail_mem) == 1) { + avail_mem *= K; + break; + } + } while (fgets(buf, sizeof(buf), fp) != nullptr); + fclose(fp); + } + if (avail_mem == static_cast(-1L)) { + avail_mem = free_memory(); + } + log_trace(os)("available memory: " JULONG_FORMAT, avail_mem); + return avail_mem; +} + +julong os::free_memory() { + return Linux::free_memory(); +} + +julong os::Linux::free_memory() { + // values in struct sysinfo are "unsigned long" + struct sysinfo si; + julong free_mem = available_memory_in_container(); + if (free_mem != static_cast(-1L)) { + log_trace(os)("free container memory: " JULONG_FORMAT, free_mem); + return free_mem; + } sysinfo(&si); - avail_mem = (julong)si.freeram * si.mem_unit; - log_trace(os)("available memory: " JULONG_FORMAT, avail_mem); - return avail_mem; + free_mem = (julong)si.freeram * si.mem_unit; + log_trace(os)("free memory: " JULONG_FORMAT, free_mem); + return free_mem; } julong os::physical_memory() { diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index e33a1af1072..a7cf69f3164 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -51,12 +51,16 @@ class os::Linux { static size_t _default_large_page_size; + static julong available_memory_in_container(); + protected: static julong _physical_memory; static pthread_t _main_thread; static julong available_memory(); + static julong free_memory(); + static int active_processor_count(); static void initialize_system_info(); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 178630f86e9..1969df3e983 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -830,6 +830,10 @@ julong os::available_memory() { return win32::available_memory(); } +julong os::free_memory() { + return win32::available_memory(); +} + julong os::win32::available_memory() { // Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect // value if total memory is larger than 4GB diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 197797078d7..937843593ff 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,6 +63,7 @@ class os::win32 { return _processor_level; } static julong available_memory(); + static julong free_memory(); static julong physical_memory() { return _physical_memory; } // load dll from Windows system directory or Windows directory diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 0671edc7390..9c9483353a4 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1011,7 +1011,7 @@ void CompileBroker::init_compiler_threads() { void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { - julong available_memory = os::available_memory(); + julong free_memory = os::free_memory(); // If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All). size_t available_cc_np = CodeCache::unallocated_capacity(CodeBlobType::MethodNonProfiled), available_cc_p = CodeCache::unallocated_capacity(CodeBlobType::MethodProfiled); @@ -1023,7 +1023,7 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { int old_c2_count = _compilers[1]->num_compiler_threads(); int new_c2_count = MIN4(_c2_count, _c2_compile_queue->size() / 2, - (int)(available_memory / (200*M)), + (int)(free_memory / (200*M)), (int)(available_cc_np / (128*K))); for (int i = old_c2_count; i < new_c2_count; i++) { @@ -1070,8 +1070,8 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { ThreadsListHandle tlh; // name() depends on the TLH. assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct)); stringStream msg; - msg.print("Added compiler thread %s (available memory: %dMB, available non-profiled code cache: %dMB)", - ct->name(), (int)(available_memory/M), (int)(available_cc_np/M)); + msg.print("Added compiler thread %s (free memory: %dMB, available non-profiled code cache: %dMB)", + ct->name(), (int)(free_memory/M), (int)(available_cc_np/M)); print_compiler_threads(msg); } } @@ -1081,7 +1081,7 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { int old_c1_count = _compilers[0]->num_compiler_threads(); int new_c1_count = MIN4(_c1_count, _c1_compile_queue->size() / 4, - (int)(available_memory / (100*M)), + (int)(free_memory / (100*M)), (int)(available_cc_p / (128*K))); for (int i = old_c1_count; i < new_c1_count; i++) { @@ -1093,8 +1093,8 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { ThreadsListHandle tlh; // name() depends on the TLH. assert(tlh.includes(ct), "ct=" INTPTR_FORMAT " exited unexpectedly.", p2i(ct)); stringStream msg; - msg.print("Added compiler thread %s (available memory: %dMB, available profiled code cache: %dMB)", - ct->name(), (int)(available_memory/M), (int)(available_cc_p/M)); + msg.print("Added compiler thread %s (free memory: %dMB, available profiled code cache: %dMB)", + ct->name(), (int)(free_memory/M), (int)(available_cc_p/M)); print_compiler_threads(msg); } } diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index c27acbc6d32..5b37715c295 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -310,7 +310,13 @@ class os: AllStatic { return (_processor_count != 1); } + // On some platforms there is a distinction between "available" memory and "free" memory. + // For example, on Linux, "available" memory (`MemAvailable` in `/proc/meminfo`) is greater + // than "free" memory (`MemFree` in `/proc/meminfo`) because Linux can free memory + // aggressively (e.g. clear caches) so that it becomes available. static julong available_memory(); + static julong free_memory(); + static julong physical_memory(); static bool has_allocatable_memory_limit(size_t* limit); static bool is_server_class_machine();