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 + -
显示快捷键?