Пример #1
0
/* Lookup or create a new TraceInfo */
static TraceInfo *
lookupOrEnter(jvmtiEnv *jvmti, Trace *trace, TraceFlavor flavor)
{
    TraceInfo *tinfo;
    jlong      hashCode;

    /* Calculate hash code (outside critical section to lessen contention) */
    hashCode = hashTrace(trace);

    /* Do a lookup in the hash table */
    enterCriticalSection(jvmti);
    {
        TraceInfo *prev;
        int        hashIndex;

        /* Start with first item in hash buck chain */
        prev = NULL;
        hashIndex = (int)(hashCode & HASH_INDEX_MASK);
        tinfo = gdata->hashBuckets[hashIndex];
        while ( tinfo != NULL ) {
            if ( tinfo->hashCode == hashCode &&
                    memcmp(trace, &(tinfo->trace), sizeof(Trace))==0 ) {
                /* We found one that matches, move to head of bucket chain */
                if ( prev != NULL ) {
                    /* Remove from list and add to head of list */
                    prev->next = tinfo->next;
                    tinfo->next = gdata->hashBuckets[hashIndex];
                    gdata->hashBuckets[hashIndex] = tinfo;
                }
                /* Break out */
                break;
            }
            prev = tinfo;
            tinfo = tinfo->next;
        }

        /* If we didn't find anything we need to enter a new entry */
        if ( tinfo == NULL ) {
            /* Create new hash table element */
            tinfo = newTraceInfo(trace, hashCode, flavor);
        }

        /* Update stats */
        (void)updateStats(tinfo);

    }
    exitCriticalSection(jvmti);

    return tinfo;
}
Пример #2
0
/* Callback for JVMTI_EVENT_VM_START */
static void JNICALL
cbVMStart(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);
}
/* Callback for JVMTI_EVENT_VM_INIT */
static void JNICALL
cbVMInit(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);
}
/* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */
static void JNICALL
cbClassFileLoadHook(jvmtiEnv *jvmti, JNIEnv* env,
                jclass class_being_redefined, jobject loader,
                const char* name, jobject protection_domain,
                jint class_data_len, const unsigned char* class_data,
                jint* new_class_data_len, unsigned char** new_class_data)
{
    enterCriticalSection(jvmti); {
        /* It's possible we get here right after VmDeath event, be careful */
        if ( !gdata->vmDead ) {

            const char * classname;

            /* Name can be NULL, make sure we avoid SEGV's */
            if ( name == NULL ) {
                classname = java_crw_demo_classname(class_data, class_data_len,
                                NULL);
                if ( classname == NULL ) {
                    fatal_error("ERROR: No classname in classfile\n");
                }
            } else {
                classname = strdup(name);
                if ( classname == NULL ) {
                    fatal_error("ERROR: Ran out of malloc() space\n");
                }
            }

            *new_class_data_len = 0;
            *new_class_data     = NULL;

            /* The tracker class itself? */
            if ( strcmp(classname, STRING(HEAP_TRACKER_class)) != 0 ) {
                jint           cnum;
                int            systemClass;
                unsigned char *newImage;
                long           newLength;

                /* Get number for every class file image loaded */
                cnum = gdata->ccount++;

                /* Is it a system class? If the class load is before VmStart
                 *   then we will consider it a system class that should
                 *   be treated carefully. (See java_crw_demo)
                 */
                systemClass = 0;
                if ( !gdata->vmStarted ) {
                    systemClass = 1;
                }

                newImage = NULL;
                newLength = 0;

                /* Call the class file reader/write demo code */
                java_crw_demo(cnum,
                    classname,
                    class_data,
                    class_data_len,
                    systemClass,
                    STRING(HEAP_TRACKER_class),
                    "L" STRING(HEAP_TRACKER_class) ";",
                    NULL, NULL,
                    NULL, NULL,
                    STRING(HEAP_TRACKER_newobj), "(Ljava/lang/Object;)V",
                    STRING(HEAP_TRACKER_newarr), "(Ljava/lang/Object;)V",
                    &newImage,
                    &newLength,
                    NULL,
                    NULL);

                /* If we got back a new class image, return it back as "the"
                 *   new class image. This must be JVMTI Allocate space.
                 */
                if ( newLength > 0 ) {
                    unsigned char *jvmti_space;

                    jvmti_space = (unsigned char *)allocate(jvmti, (jint)newLength);
                    (void)memcpy((void*)jvmti_space, (void*)newImage, (int)newLength);
                    *new_class_data_len = (jint)newLength;
                    *new_class_data     = jvmti_space; /* VM will deallocate */
                }

                /* Always free up the space we get from java_crw_demo() */
                if ( newImage != NULL ) {
                    (void)free((void*)newImage); /* Free malloc() space with free() */
                }
            }
        
            (void)free((void*)classname);
        }
    } exitCriticalSection(jvmti);
}
/* Callback for JVMTI_EVENT_VM_DEATH */
static void JNICALL
cbVMDeath(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");

            /* Create single array of pointers to TraceInfo's, sort, and
             *   print top gdata->maxDump top space users.
             */
            list = (TraceInfo**)calloc(gdata->traceInfoCount, 
                                              sizeof(TraceInfo*));
            if ( list == NULL ) {
                fatal_error("ERROR: Ran out of malloc() space\n");
            }
            count = 0;
            for ( i = 0 ; i < HASH_BUCKET_COUNT ; i++ ) {
                TraceInfo *tinfo;

                tinfo = gdata->hashBuckets[i];
                while ( tinfo != NULL ) {
                    if ( count < gdata->traceInfoCount ) {
                        list[count++] = tinfo;
                    }
                    tinfo = tinfo->next;
                }
            }
            if ( count != gdata->traceInfoCount ) {
                fatal_error("ERROR: Count found by iterate doesn't match ours:"
                        " count=%d != traceInfoCount==%d\n",
                        count, gdata->traceInfoCount);
            }
            qsort(list, count, sizeof(TraceInfo*), &compareInfo);
            for ( i = 0 ; i < count ; i++ ) {
                if ( i >= gdata->maxDump ) {
                    break;
                }
                printTraceInfo(jvmti, i+1, list[i]);
            }
            (void)free(list);
        }

    } exitCriticalSection(jvmti);
        
}