heaptracker.c
来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 1,014 行 · 第 1/3 页
C
1,014 行
jlong tag; /* Tag this object with this TraceInfo pointer */ tag = (jlong)(ptrdiff_t)(void*)tinfo; error = (*jvmti)->SetTag(jvmti, object, tag); check_jvmti_error(jvmti, error, "Cannot tag object");}/* Java Native Method for Object.<init> */static voidHEAP_TRACKER_native_newobj(JNIEnv *env, jclass klass, jthread thread, jobject o){ TraceInfo *tinfo; if ( gdata->vmDead ) { return; } tinfo = findTraceInfo(gdata->jvmti, thread, TRACE_USER); tagObjectWithTraceInfo(gdata->jvmti, o, tinfo);}/* Java Native Method for newarray */static voidHEAP_TRACKER_native_newarr(JNIEnv *env, jclass klass, jthread thread, jobject a){ TraceInfo *tinfo; if ( gdata->vmDead ) { return; } tinfo = findTraceInfo(gdata->jvmti, thread, TRACE_USER); tagObjectWithTraceInfo(gdata->jvmti, a, tinfo);}/* Callback for JVMTI_EVENT_VM_START */static void JNICALLcbVMStart(jvmtiEnv *jvmti, JNIEnv *env){ enterCriticalSection(jvmti); { jclass klass; jfieldID field; jint rc; /* Java Native Methods for class */ static JNINativeMethod registry[2] = { {STRING(HEAP_TRACKER_native_newobj), "(Ljava/lang/Object;Ljava/lang/Object;)V", (void*)&HEAP_TRACKER_native_newobj}, {STRING(HEAP_TRACKER_native_newarr), "(Ljava/lang/Object;Ljava/lang/Object;)V", (void*)&HEAP_TRACKER_native_newarr} }; /* Register Natives for class whose methods we use */ klass = (*env)->FindClass(env, STRING(HEAP_TRACKER_class)); if ( klass == NULL ) { fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", STRING(HEAP_TRACKER_class)); } rc = (*env)->RegisterNatives(env, klass, registry, 2); if ( rc != 0 ) { fatal_error("ERROR: JNI: Cannot register natives for class %s\n", STRING(HEAP_TRACKER_class)); } /* Engage calls. */ field = (*env)->GetStaticFieldID(env, klass, STRING(HEAP_TRACKER_engaged), "I"); if ( field == NULL ) { fatal_error("ERROR: JNI: Cannot get field from %s\n", STRING(HEAP_TRACKER_class)); } (*env)->SetStaticIntField(env, klass, field, 1); /* Indicate VM has started */ gdata->vmStarted = JNI_TRUE; } exitCriticalSection(jvmti);}/* Iterate Through Heap callback */static jint JNICALLcbObjectTagger(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void *user_data){ TraceInfo *tinfo; tinfo = emptyTrace(TRACE_BEFORE_VM_INIT); *tag_ptr = (jlong)(ptrdiff_t)(void*)tinfo; return JVMTI_VISIT_OBJECTS;}/* Callback for JVMTI_EVENT_VM_INIT */static void JNICALLcbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread){ jvmtiHeapCallbacks heapCallbacks; jvmtiError error; /* Iterate through heap, find all untagged objects allocated before this */ (void)memset(&heapCallbacks, 0, sizeof(heapCallbacks)); heapCallbacks.heap_iteration_callback = &cbObjectTagger; error = (*jvmti)->IterateThroughHeap(jvmti, JVMTI_HEAP_FILTER_TAGGED, NULL, &heapCallbacks, NULL); check_jvmti_error(jvmti, error, "Cannot iterate through heap"); enterCriticalSection(jvmti); { /* Indicate VM is initialized */ gdata->vmInitialized = JNI_TRUE; } exitCriticalSection(jvmti);}/* Iterate Through Heap callback */static jint JNICALLcbObjectSpaceCounter(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void *user_data){ TraceInfo *tinfo; tinfo = (TraceInfo*)(ptrdiff_t)(*tag_ptr); if ( tinfo == NULL ) { tinfo = emptyTrace(TRACE_MYSTERY); *tag_ptr = (jlong)(ptrdiff_t)(void*)tinfo; } tinfo->totalSpace += size; return JVMTI_VISIT_OBJECTS;}/* Qsort compare function */static intcompareInfo(const void *p1, const void *p2){ TraceInfo *tinfo1, *tinfo2; tinfo1 = *((TraceInfo**)p1); tinfo2 = *((TraceInfo**)p2); return (int)(tinfo2->totalSpace - tinfo1->totalSpace);}/* Frame to text */static voidframeToString(jvmtiEnv *jvmti, char *buf, int buflen, jvmtiFrameInfo *finfo){ jvmtiError error; jclass klass; char *signature; char *methodname; char *methodsig; jboolean isNative; char *filename; int lineCount; jvmtiLineNumberEntry*lineTable; int lineNumber; /* Initialize defaults */ buf[0] = 0; klass = NULL; signature = NULL; methodname = NULL; methodsig = NULL; isNative = JNI_FALSE; filename = NULL; lineCount = 0; lineTable = NULL; lineNumber = 0; /* Get jclass object for the jmethodID */ error = (*jvmti)->GetMethodDeclaringClass(jvmti, finfo->method, &klass); check_jvmti_error(jvmti, error, "Cannot get method's class"); /* Get the class signature */ error = (*jvmti)->GetClassSignature(jvmti, klass, &signature, NULL); check_jvmti_error(jvmti, error, "Cannot get class signature"); /* Skip all this if it's our own Tracker method */ if ( strcmp(signature, "L" STRING(HEAP_TRACKER_class) ";" ) == 0 ) { deallocate(jvmti, signature); return; } /* Get the name and signature for the method */ error = (*jvmti)->GetMethodName(jvmti, finfo->method, &methodname, &methodsig, NULL); check_jvmti_error(jvmti, error, "Cannot method name"); /* Check to see if it's a native method, which means no lineNumber */ error = (*jvmti)->IsMethodNative(jvmti, finfo->method, &isNative); check_jvmti_error(jvmti, error, "Cannot get method native status"); /* Get source file name */ error = (*jvmti)->GetSourceFileName(jvmti, klass, &filename); if ( error != JVMTI_ERROR_NONE && error != JVMTI_ERROR_ABSENT_INFORMATION ) { check_jvmti_error(jvmti, error, "Cannot get source filename"); } /* Get lineNumber if we can */ if ( !isNative ) { int i; /* Get method line table */ error = (*jvmti)->GetLineNumberTable(jvmti, finfo->method, &lineCount, &lineTable); if ( error == JVMTI_ERROR_NONE ) { /* Search for line */ lineNumber = lineTable[0].line_number; for ( i = 1 ; i < lineCount ; i++ ) { if ( finfo->location < lineTable[i].start_location ) { break; } lineNumber = lineTable[i].line_number; } } else if ( error != JVMTI_ERROR_ABSENT_INFORMATION ) { check_jvmti_error(jvmti, error, "Cannot get method line table"); } } /* Create string for this frame location. * NOTE: These char* quantities are mUTF (Modified UTF-8) bytes * and should actually be converted to the default system * character encoding. Sending them to things like * printf() without converting them is actually an I18n * (Internationalization) error. */ (void)sprintf(buf, "%s.%s@%d[%s:%d]", (signature==NULL?"UnknownClass":signature), (methodname==NULL?"UnknownMethod":methodname), (int)finfo->location, (filename==NULL?"UnknownFile":filename), lineNumber); /* Free up JVMTI space allocated by the above calls */ deallocate(jvmti, signature); deallocate(jvmti, methodname); deallocate(jvmti, methodsig); deallocate(jvmti, filename); deallocate(jvmti, lineTable);}/* Print the information */static voidprintTraceInfo(jvmtiEnv *jvmti, int index, TraceInfo* tinfo){ if ( tinfo == NULL ) { fatal_error("%d: NULL ENTRY ERROR\n", index); return; } stdout_message("%2d: %7d bytes %5d objects %5d live %s", index, (int)tinfo->totalSpace, tinfo->totalCount, tinfo->useCount, flavorDesc[tinfo->trace.flavor]); if ( tinfo->trace.nframes > 0 ) { int i; int fcount; fcount = 0; stdout_message(" stack=("); for ( i = 0 ; i < tinfo->trace.nframes ; i++ ) { char buf[4096]; frameToString(jvmti, buf, (int)sizeof(buf), tinfo->trace.frames+i); if ( buf[0] == 0 ) { continue; /* Skip the ones that are from Tracker class */ } fcount++; stdout_message("%s", buf); if ( i < (tinfo->trace.nframes-1) ) { stdout_message(","); } } stdout_message(") nframes=%d\n", fcount); } else { stdout_message(" stack=<empty>\n"); }}/* Callback for JVMTI_EVENT_VM_DEATH */static void JNICALLcbVMDeath(jvmtiEnv *jvmti, JNIEnv *env){ jvmtiHeapCallbacks heapCallbacks; jvmtiError error; /* These are purposely done outside the critical section */ /* Force garbage collection now so we get our ObjectFree calls */ error = (*jvmti)->ForceGarbageCollection(jvmti); check_jvmti_error(jvmti, error, "Cannot force garbage collection"); /* Iterate through heap and find all objects */ (void)memset(&heapCallbacks, 0, sizeof(heapCallbacks)); heapCallbacks.heap_iteration_callback = &cbObjectSpaceCounter; error = (*jvmti)->IterateThroughHeap(jvmti, 0, NULL, &heapCallbacks, NULL); check_jvmti_error(jvmti, error, "Cannot iterate through heap"); /* Process VM Death */ enterCriticalSection(jvmti); { jclass klass; jfieldID field; jvmtiEventCallbacks callbacks; /* Disengage calls in HEAP_TRACKER_class. */ klass = (*env)->FindClass(env, STRING(HEAP_TRACKER_class)); if ( klass == NULL ) { fatal_error("ERROR: JNI: Cannot find %s with FindClass\n", STRING(HEAP_TRACKER_class)); } field = (*env)->GetStaticFieldID(env, klass, STRING(HEAP_TRACKER_engaged), "I"); if ( field == NULL ) { fatal_error("ERROR: JNI: Cannot get field from %s\n", STRING(HEAP_TRACKER_class)); } (*env)->SetStaticIntField(env, klass, field, 0); /* The critical section here is important to hold back the VM death * until all other callbacks have completed. */ /* Clear out all callbacks. */ (void)memset(&callbacks,0, sizeof(callbacks)); error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks"); /* Since this critical section could be holding up other threads * in other event callbacks, we need to indicate that the VM is * dead so that the other callbacks can short circuit their work. * We don't expect an further events after VmDeath but we do need * to be careful that existing threads might be in our own agent * callback code. */ gdata->vmDead = JNI_TRUE; /* Dump all objects */ if ( gdata->traceInfoCount > 0 ) { TraceInfo **list; int count; int i; stdout_message("Dumping heap trace information\n");
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?