heaptracker.c
来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 1,014 行 · 第 1/3 页
C
1,014 行
/* 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); } /* Callback for JVMTI_EVENT_VM_OBJECT_ALLOC */static void JNICALLcbVMObjectAlloc(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jobject object, jclass object_klass, jlong size){ TraceInfo *tinfo; if ( gdata->vmDead ) { return; } tinfo = findTraceInfo(jvmti, thread, TRACE_VM_OBJECT); tagObjectWithTraceInfo(jvmti, object, tinfo);}/* Callback for JVMTI_EVENT_OBJECT_FREE */static void JNICALLcbObjectFree(jvmtiEnv *jvmti, jlong tag){ TraceInfo *tinfo; if ( gdata->vmDead ) { return; } /* The object tag is actually a pointer to a TraceInfo structure */ tinfo = (TraceInfo*)(void*)(ptrdiff_t)tag; /* Decrement the use count */ tinfo->useCount--;}/* Callback for JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */static void JNICALLcbClassFileLoadHook(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);}/* Parse the options for this heapTracker agent */static voidparse_agent_options(char *options){ #define MAX_TOKEN_LENGTH 16 char token[MAX_TOKEN_LENGTH]; char *next; /* Defaults */ gdata->maxDump = 20; /* Parse options and set flags in gdata */ if ( options==NULL ) { return; } /* Get the first token from the options string. */ next = get_token(options, ",=", token, (int)sizeof(token)); /* While not at the end of the options string, process this option. */ while ( next != NULL ) { if ( strcmp(token,"help")==0 ) { stdout_message("The heapTracker JVMTI demo agent\n"); stdout_message("\n"); stdout_message(" java -agent:heapTracker[=options] ...\n"); stdout_message("\n"); stdout_message("The options are comma separated:\n"); stdout_message("\t help\t\t\t Print help information\n"); stdout_message("\t maxDump=n\t\t\t How many TraceInfo's to dump\n"); stdout_message("\n"); exit(0); } else if ( strcmp(token,"maxDump")==0 ) { char number[MAX_TOKEN_LENGTH]; next = get_token(next, ",=", number, (int)sizeof(number)); if ( next == NULL ) { fatal_error("ERROR: Cannot parse maxDump=number: %s\n", options); } gdata->maxDump = atoi(number); } else if ( token[0]!=0 ) { /* We got a non-empty token and we don't know what it is. */ fatal_error("ERROR: Unknown option: %s\n", token); } /* Get the next token (returns NULL if there are no more) */ next = get_token(next, ",=", token, (int)sizeof(token)); }}/* Agent_OnLoad: This is called immediately after the shared library is * loaded. This is the first code executed. */JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved){ static GlobalAgentData data; jvmtiEnv *jvmti; jvmtiError error; jint res; TraceFlavor flavor; jvmtiCapabilities capabilities; jvmtiEventCallbacks callbacks; static Trace empty; /* Setup initial global agent data area * Use of static/extern data should be handled carefully here. * We need to make sure that we are able to cleanup after ourselves * so anything allocated in this library needs to be freed in * the Agent_OnUnload() function. */ (void)memset((void*)&data, 0, sizeof(data)); gdata = &data; /* First thing we need to do is get the jvmtiEnv* or JVMTI environment */ res = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1); if (res != JNI_OK) { /* This means that the VM was unable to obtain this version of the * JVMTI interface, this is a fatal error. */ fatal_error("ERROR: Unable to access JVMTI Version 1 (0x%x)," " is your JDK a 5.0 or newer version?" " JNIEnv's GetEnv() returned %d\n", JVMTI_VERSION_1, res); } /* Here we save the jvmtiEnv* for Agent_OnUnload(). */ gdata->jvmti = jvmti; /* Parse any options supplied on java command line */ parse_agent_options(options); /* Immediately after getting the jvmtiEnv* we need to ask for the * capabilities this agent will need. */ (void)memset(&capabilities,0, sizeof(capabilities)); capabilities.can_generate_all_class_hook_events = 1; capabilities.can_tag_objects = 1; capabilities.can_generate_object_free_events = 1; capabilities.can_get_source_file_name = 1; capabilities.can_get_line_numbers = 1; capabilities.can_generate_vm_object_alloc_events = 1; error = (*jvmti)->AddCapabilities(jvmti, &capabilities); check_jvmti_error(jvmti, error, "Unable to get necessary JVMTI capabilities."); /* Next we need to provide the pointers to the callback functions to * to this jvmtiEnv* */ (void)memset(&callbacks,0, sizeof(callbacks)); /* JVMTI_EVENT_VM_START */ callbacks.VMStart = &cbVMStart; /* JVMTI_EVENT_VM_INIT */ callbacks.VMInit = &cbVMInit; /* JVMTI_EVENT_VM_DEATH */ callbacks.VMDeath = &cbVMDeath; /* JVMTI_EVENT_OBJECT_FREE */ callbacks.ObjectFree = &cbObjectFree; /* JVMTI_EVENT_VM_OBJECT_ALLOC */ callbacks.VMObjectAlloc = &cbVMObjectAlloc; /* JVMTI_EVENT_CLASS_FILE_LOAD_HOOK */ callbacks.ClassFileLoadHook = &cbClassFileLoadHook; error = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, (jint)sizeof(callbacks)); check_jvmti_error(jvmti, error, "Cannot set jvmti callbacks"); /* At first the only initial events we are interested in are VM * initialization, VM death, and Class File Loads. * Once the VM is initialized we will request more events. */ error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_START, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_OBJECT_FREE, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); error = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, (jthread)NULL); check_jvmti_error(jvmti, error, "Cannot set event notification"); /* Here we create a raw monitor for our use in this agent to * protect critical sections of code. */ error = (*jvmti)->CreateRawMonitor(jvmti, "agent data", &(gdata->lock)); check_jvmti_error(jvmti, error, "Cannot create raw monitor"); /* Create the TraceInfo for various flavors of empty traces */ for ( flavor = TRACE_FIRST ; flavor <= TRACE_LAST ; flavor++ ) { gdata->emptyTrace[flavor] = newTraceInfo(&empty, hashTrace(&empty), flavor); } /* Add jar file to boot classpath */ add_demo_jar_to_bootclasspath(jvmti, "heapTracker"); /* We return JNI_OK to signify success */ return JNI_OK;}/* Agent_OnUnload: This is called immediately before the shared library is * unloaded. This is the last code executed. */JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm){ /* Skip any cleanup, VM is about to die anyway */}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?