hprof_init.c
来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 1,986 行 · 第 1/5 页
C
1,986 行
if ( gdata->debug ) { gdata->logflags |= LOG_CHECK_BINARY; } gdata->heap_fd = md_creat_binary(gdata->heapfilename); } else { gdata->heap_fd = md_creat(gdata->heapfilename); } if ( gdata->heap_fd < 0 ) { char errmsg[FILENAME_MAX+80]; (void)md_snprintf(errmsg, sizeof(errmsg), "can't create temp heap file: %s", gdata->heapfilename); errmsg[sizeof(errmsg)-1] = 0; HPROF_ERROR(JNI_TRUE, errmsg); } } if ( gdata->net_port > 0 ) { LOG2("Agent_OnLoad", "Connecting to socket"); gdata->fd = connect_to_socket(gdata->net_hostname, (unsigned short)gdata->net_port); if (gdata->fd <= 0) { char errmsg[120]; (void)md_snprintf(errmsg, sizeof(errmsg), "can't connect to %s:%u", gdata->net_hostname, gdata->net_port); errmsg[sizeof(errmsg)-1] = 0; HPROF_ERROR(JNI_FALSE, errmsg); error_exit_process(1); } gdata->socket = JNI_TRUE; } else { /* If going out to a file, obey the force=y|n option */ if ( !gdata->force_output ) { make_unique_filename(&(gdata->output_filename)); } /* Make doubly sure this file does NOT exist */ (void)remove(gdata->output_filename); /* Create the file */ if (gdata->output_format == 'b') { gdata->fd = md_creat_binary(gdata->output_filename); } else { gdata->fd = md_creat(gdata->output_filename); } if (gdata->fd < 0) { char errmsg[FILENAME_MAX+80]; (void)md_snprintf(errmsg, sizeof(errmsg), "can't create profile file: %s", gdata->output_filename); errmsg[sizeof(errmsg)-1] = 0; HPROF_ERROR(JNI_FALSE, errmsg); error_exit_process(1); } }}/* ------------------------------------------------------------------- *//* Data reset and dump functions */static void reset_all_data(void){ if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) { rawMonitorEnter(gdata->data_access_lock); } if (gdata->cpu_sampling || gdata->cpu_timing) { trace_clear_cost(); } if (gdata->monitor_tracing) { monitor_clear(); } if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) { rawMonitorExit(gdata->data_access_lock); }}static void reset_class_load_status(JNIEnv *env, jthread thread);static void dump_all_data(JNIEnv *env){ verbose_message("Dumping"); if (gdata->monitor_tracing) { verbose_message(" contended monitor usage ..."); tls_dump_monitor_state(env); monitor_write_contended_time(env, gdata->cutoff_point); } if (gdata->heap_dump) { verbose_message(" Java heap ..."); /* Update the class table */ reset_class_load_status(env, NULL); site_heapdump(env); } if (gdata->alloc_sites) { verbose_message(" allocation sites ..."); site_write(env, 0, gdata->cutoff_point); } if (gdata->cpu_sampling) { verbose_message(" CPU usage by sampling running threads ..."); trace_output_cost(env, gdata->cutoff_point); } if (gdata->cpu_timing) { if (!gdata->old_timing_format) { verbose_message(" CPU usage by timing methods ..."); trace_output_cost(env, gdata->cutoff_point); } else { verbose_message(" CPU usage in old prof format ..."); trace_output_cost_in_prof_format(env); } } reset_all_data(); io_flush(); verbose_message(" done.\n");}/* ------------------------------------------------------------------- *//* Dealing with class load and unload status */static voidreset_class_load_status(JNIEnv *env, jthread thread){ WITH_LOCAL_REFS(env, 1) { jint class_count; jclass *classes; jint i; /* Get all classes from JVMTI, make sure they are in the class table. */ getLoadedClasses(&classes, &class_count); /* We don't know if the class list has changed really, so we * guess by the class count changing. Don't want to do * a bunch of work on classes when it's unnecessary. * I assume that even though we have global references on the * jclass object that the class is still considered unloaded. * (e.g. GC of jclass isn't required for it to be included * in the unloaded list, or not in the load list) * [Note: Use of Weak references was a performance problem.] */ if ( class_count != gdata->class_count ) { rawMonitorEnter(gdata->data_access_lock); { /* Unmark the classes in the load list */ class_all_status_remove(CLASS_IN_LOAD_LIST); /* Pretend like it was a class load event */ for ( i = 0 ; i < class_count ; i++ ) { jobject loader; loader = getClassLoader(classes[i]); event_class_load(env, thread, classes[i], loader); } /* Process the classes that have been unloaded */ class_do_unloads(env); } rawMonitorExit(gdata->data_access_lock); } /* Free the space and save the count. */ jvmtiDeallocate(classes); gdata->class_count = class_count; } END_WITH_LOCAL_REFS;}/* A GC or Death event has happened, so do some cleanup */static voidobject_free_cleanup(JNIEnv *env, jboolean force_class_table_reset){ Stack *stack; /* Then we process the ObjectFreeStack */ rawMonitorEnter(gdata->object_free_lock); { stack = gdata->object_free_stack; gdata->object_free_stack = NULL; /* Will trigger new stack */ } rawMonitorExit(gdata->object_free_lock); /* Notice we just grabbed the stack of freed objects so * any object free events will create a new stack. */ if ( stack != NULL ) { int count; int i; count = stack_depth(stack); /* If we saw something freed in this GC */ if ( count > 0 ) { for ( i = 0 ; i < count ; i++ ) { ObjectIndex object_index; jlong tag; tag = *(jlong*)stack_element(stack,i); object_index = tag_extract(tag); (void)object_free(object_index); } /* We reset the class load status (only do this once) */ reset_class_load_status(env, NULL); force_class_table_reset = JNI_FALSE; } /* Just terminate this stack object */ stack_term(stack); } /* We reset the class load status if we haven't and need to */ if ( force_class_table_reset ) { reset_class_load_status(env, NULL); } }/* Main function for thread that watches for GC finish events */static void JNICALLgc_finish_watcher(jvmtiEnv *jvmti, JNIEnv *env, void *p){ jboolean active; active = JNI_TRUE; /* Indicate the watcher thread is active */ rawMonitorEnter(gdata->gc_finish_lock); { gdata->gc_finish_active = JNI_TRUE; } rawMonitorExit(gdata->gc_finish_lock); /* Loop while active */ while ( active ) { jboolean do_cleanup; do_cleanup = JNI_FALSE; rawMonitorEnter(gdata->gc_finish_lock); { /* Don't wait if VM_DEATH wants us to quit */ if ( gdata->gc_finish_stop_request ) { /* Time to terminate */ active = JNI_FALSE; } else { /* Wait for notification to do cleanup, or terminate */ rawMonitorWait(gdata->gc_finish_lock, 0); /* After wait, check to see if VM_DEATH wants us to quit */ if ( gdata->gc_finish_stop_request ) { /* Time to terminate */ active = JNI_FALSE; } } if ( active && gdata->gc_finish > 0 ) { /* Time to cleanup, reset count and prepare for cleanup */ gdata->gc_finish = 0; do_cleanup = JNI_TRUE; } } rawMonitorExit(gdata->gc_finish_lock); /* Do the cleanup if requested outside gc_finish_lock */ if ( do_cleanup ) { /* Free up all freed objects, don't force class table reset * We cannot let the VM_DEATH complete while we are doing * this cleanup. So if during this, VM_DEATH happens, * the VM_DEATH callback should block waiting for this * loop to terminate, and send a notification to the * VM_DEATH thread. */ object_free_cleanup(env, JNI_FALSE); /* Cleanup the tls table where the Thread objects were GC'd */ tls_garbage_collect(env); } } /* Falling out means VM_DEATH is happening, we need to notify VM_DEATH * that we are done doing the cleanup. VM_DEATH is waiting on this * notify. */ rawMonitorEnter(gdata->gc_finish_lock); { gdata->gc_finish_active = JNI_FALSE; rawMonitorNotifyAll(gdata->gc_finish_lock); } rawMonitorExit(gdata->gc_finish_lock);}/* ------------------------------------------------------------------- *//* JVMTI Event callback functions */static voidsetup_event_mode(jboolean onload_set_only, jvmtiEventMode state){ if ( onload_set_only ) { setEventNotificationMode(state, JVMTI_EVENT_VM_INIT, NULL); setEventNotificationMode(state, JVMTI_EVENT_VM_DEATH, NULL); if (gdata->bci) { setEventNotificationMode(state, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); } } else { /* Enable all other JVMTI events of interest now. */ setEventNotificationMode(state, JVMTI_EVENT_THREAD_START, NULL); setEventNotificationMode(state, JVMTI_EVENT_THREAD_END, NULL); setEventNotificationMode(state, JVMTI_EVENT_CLASS_LOAD, NULL); setEventNotificationMode(state, JVMTI_EVENT_CLASS_PREPARE, NULL); setEventNotificationMode(state, JVMTI_EVENT_DATA_DUMP_REQUEST, NULL); if (gdata->cpu_timing) { setEventNotificationMode(state, JVMTI_EVENT_EXCEPTION_CATCH, NULL); } if (gdata->monitor_tracing) { setEventNotificationMode(state, JVMTI_EVENT_MONITOR_WAIT, NULL); setEventNotificationMode(state, JVMTI_EVENT_MONITOR_WAITED, NULL); setEventNotificationMode(state, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL); setEventNotificationMode(state, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL); } if (gdata->obj_watch) { setEventNotificationMode(state, JVMTI_EVENT_OBJECT_FREE, NULL); } setEventNotificationMode(state, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL); setEventNotificationMode(state, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL); } } /* JVMTI_EVENT_VM_INIT */static void JNICALLcbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread){ rawMonitorEnter(gdata->data_access_lock); { LoaderIndex loader_index; ClassIndex cnum; TlsIndex tls_index; gdata->jvm_initializing = JNI_TRUE; /* Header to use in heap dumps */ gdata->header = "JAVA PROFILE 1.0.1"; gdata->segmented = JNI_FALSE; if (gdata->output_format == 'b') { /* We need JNI here to call in and get the current maximum memory */ gdata->maxMemory = getMaxMemory(env); gdata->maxHeapSegment = (jlong)2000000000; /* More than 2Gig triggers segments and 1.0.2 */ if ( gdata->maxMemory >= gdata->maxHeapSegment ) { gdata->header = "JAVA PROFILE 1.0.2"; gdata->segmented = JNI_TRUE; /* 1.0.2 */ } } /* We write the initial header after the VM initializes now * because we needed to use JNI to get maxMemory and determine if * a 1.0.1 or a 1.0.2 header will be used. * This used to be done in Agent_OnLoad. */ io_write_file_header(); LOG("cbVMInit begin"); /* Create a system loader entry first */ loader_index = loader_find_or_create(NULL,NULL); /* Find the thread jclass (does JNI calls) */ gdata->thread_cnum = class_find_or_create("Ljava/lang/Thread;", loader_index); class_add_status(gdata->thread_cnum, CLASS_SYSTEM); /* Issue fake system thread start */ tls_index = tls_find_or_create(env, thread); /* Setup the Tracker class (should be first class in table) */ tracker_setup_class(); /* Find selected system classes to keep track of */ gdata->system_class_size = 0; cnum = class_find_or_create("Ljava/lang/Object;", loader_index); gdata->system_trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, JNI_FALSE); gdata->system_object_site_index = site_find_or_create( cnum, gdata->system_trace_index);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?