diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 53ac0aabb..3b10c14d1 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -148,7 +148,7 @@ void VMStructs::ready() { JNIEnv *env = VM::jni(); initThreadBridge(env); initLogging(env); - initMemoryUsage(env); + HeapUsage::initJMXUsage(env); _libjvm->dump(); } @@ -637,17 +637,43 @@ void VMStructs::initLogging(JNIEnv *env) { } } -void VMStructs::initMemoryUsage(JNIEnv *env) { +bool HeapUsage::is_jmx_attempted = false; +bool HeapUsage::is_jmx_supported = false; // default to not-supported + +void HeapUsage::initJMXUsage(JNIEnv *env) { + if (is_jmx_attempted) { + // do not re-run the initialization + return; + } + is_jmx_attempted = true; jclass factory = env->FindClass("java/lang/management/ManagementFactory"); + if (!jniExceptionCheck(env) || factory == nullptr) { + return; + } jclass memoryBeanClass = env->FindClass("java/lang/management/MemoryMXBean"); + if (!jniExceptionCheck(env) || memoryBeanClass == nullptr) { + return; + } jmethodID get_memory = env->GetStaticMethodID( factory, "getMemoryMXBean", "()Ljava/lang/management/MemoryMXBean;"); + if (!jniExceptionCheck(env) || get_memory == nullptr) { + return; + } jobject memoryBean = env->CallStaticObjectMethod(factory, get_memory); - jniExceptionCheck(env); + if (!jniExceptionCheck(env) || memoryBean == nullptr) { + return; + } jmethodID get_heap = env->GetMethodID(memoryBeanClass, "getHeapMemoryUsage", "()Ljava/lang/management/MemoryUsage;"); + if (!jniExceptionCheck(env) || get_heap == nullptr) { + return; + } env->CallObjectMethod(memoryBean, get_heap); - jniExceptionCheck(env); + if (!jniExceptionCheck(env)) { + return; + } + // mark JMX as supported only after we were able to retrieve the memory usage + is_jmx_supported = true; } VMThread *VMThread::current() { diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 3ba95f47b..f6ede92f1 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -570,13 +570,26 @@ class JVMFlag : VMStructs { }; class HeapUsage : VMStructs { +private: + static bool is_jmx_attempted; + static bool is_jmx_supported; // default to not-supported public: + + size_t _initSize = -1; size_t _used = -1; size_t _committed = -1; size_t _maxSize = -1; size_t _used_at_last_gc = -1; + static void initJMXUsage(JNIEnv* env); + + static bool isJMXSupported() { + initJMXUsage(VM::jni()); + return is_jmx_supported; + } + + static bool isLastGCUsageSupported() { // only supported for JDK 17+ // the CollectedHeap structure is vastly different in JDK 11 and earlier so @@ -638,7 +651,7 @@ class HeapUsage : VMStructs { usage._maxSize = summary.maxSize(); } } - if (usage._maxSize == -1 && _memory_usage_func != NULL && allow_jmx) { + if (usage._maxSize == -1 && _memory_usage_func != NULL && allow_jmx && isJMXSupported()) { // this path is for non-hotspot JVMs // we need to patch the native method binding for JMX GetMemoryUsage to // capture the native method pointer first also, it requires JMX and