4747#include " runtime/interfaceSupport.inline.hpp"
4848#include " runtime/javaCalls.hpp"
4949#include " runtime/jniHandles.inline.hpp"
50+ #include " runtime/mutexLocker.hpp"
5051#include " runtime/notificationThread.hpp"
5152#include " runtime/os.hpp"
5253#include " runtime/thread.inline.hpp"
@@ -428,8 +429,6 @@ static MemoryPool* get_memory_pool_from_jobject(jobject obj, TRAPS) {
428429 return MemoryService::get_memory_pool (ph);
429430}
430431
431- #endif // INCLUDE_MANAGEMENT
432-
433432static void validate_thread_id_array (typeArrayHandle ids_ah, TRAPS) {
434433 int num_threads = ids_ah->length ();
435434
@@ -455,8 +454,6 @@ static bool is_platform_thread(JavaThread* jt) {
455454 }
456455}
457456
458- #if INCLUDE_MANAGEMENT
459-
460457static void validate_thread_info_array (objArrayHandle infoArray_h, TRAPS) {
461458 // check if the element of infoArray is of type ThreadInfo class
462459 Klass* threadinfo_klass = Management::java_lang_management_ThreadInfo_klass (CHECK);
@@ -2095,7 +2092,41 @@ jlong Management::ticks_to_ms(jlong ticks) {
20952092 return (jlong)(((double )ticks / (double )os::elapsed_frequency ())
20962093 * (double )1000.0 );
20972094}
2098- #endif // INCLUDE_MANAGEMENT
2095+
2096+ // Gets the amount of memory allocated on the Java heap since JVM launch.
2097+ JVM_ENTRY (jlong, jmm_GetTotalThreadAllocatedMemory(JNIEnv *env))
2098+ // A thread increments exited_allocated_bytes in ThreadService::remove_thread
2099+ // only after it removes itself from the threads list, and once a TLH is
2100+ // created, no thread it references can remove itself from the threads
2101+ // list, so none can update exited_allocated_bytes. We therefore initialize
2102+ // result with exited_allocated_bytes after after we create the TLH so that
2103+ // the final result can only be short due to (1) threads that start after
2104+ // the TLH is created, or (2) terminating threads that escape TLH creation
2105+ // and don't update exited_allocated_bytes before we initialize result.
2106+
2107+ // We keep a high water mark to ensure monotonicity in case threads counted
2108+ // on a previous call end up in state (2).
2109+ static jlong high_water_result = 0;
2110+
2111+ JavaThreadIteratorWithHandle jtiwh;
2112+ jlong result = ThreadService::exited_allocated_bytes();
2113+ for (; JavaThread* thread = jtiwh.next();) {
2114+ jlong size = thread->cooked_allocated_bytes ();
2115+ result += size;
2116+ }
2117+
2118+ {
2119+ MutexLocker ml (MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
2120+ if (result < high_water_result) {
2121+ // Encountered (2) above, or result wrapped to a negative value. In
2122+ // the latter case, it's pegged at the last positive value.
2123+ result = high_water_result;
2124+ } else {
2125+ high_water_result = result;
2126+ }
2127+ }
2128+ return result;
2129+ JVM_END
20992130
21002131// Gets the amount of memory allocated on the Java heap for a single thread.
21012132// Returns -1 if the thread does not exist or has terminated.
@@ -2228,9 +2259,6 @@ JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids,
22282259 }
22292260JVM_END
22302261
2231-
2232-
2233- #if INCLUDE_MANAGEMENT
22342262const struct jmmInterface_1_ jmm_interface = {
22352263 nullptr ,
22362264 nullptr ,
@@ -2241,6 +2269,7 @@ const struct jmmInterface_1_ jmm_interface = {
22412269 jmm_GetMemoryManagers,
22422270 jmm_GetMemoryPoolUsage,
22432271 jmm_GetPeakMemoryPoolUsage,
2272+ jmm_GetTotalThreadAllocatedMemory,
22442273 jmm_GetOneThreadAllocatedMemory,
22452274 jmm_GetThreadAllocatedMemory,
22462275 jmm_GetMemoryUsage,
0 commit comments