heaptracker.c
来自「一个小公司要求给写的很简单的任务管理系统。」· C语言 代码 · 共 1,014 行 · 第 1/3 页
C
1,014 行
/* * @(#)heapTracker.c 1.21 06/02/16 * * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */#include "stdlib.h"#include "heapTracker.h"#include "java_crw_demo.h"#include "jni.h"#include "jvmti.h"#include "agent_util.h"/* ------------------------------------------------------------------- * Some constant names that tie to Java class/method names. * We assume the Java class whose static methods we will be calling * looks like: * * public class HeapTracker { * private static int engaged; * private static native void _newobj(Object thr, Object o); * public static void newobj(Object o) * { * if ( engaged != 0 ) { * _newobj(Thread.currentThread(), o); * } * } * private static native void _newarr(Object thr, Object a); * public static void newarr(Object a) * { * if ( engaged != 0 ) { * _newarr(Thread.currentThread(), a); * } * } * } * * The engaged field allows us to inject all classes (even system classes) * and delay the actual calls to the native code until the VM has reached * a safe time to call native methods (Past the JVMTI VM_START event). * */#define HEAP_TRACKER_class HeapTracker /* Name of class we are using */#define HEAP_TRACKER_newobj newobj /* Name of java init method */#define HEAP_TRACKER_newarr newarr /* Name of java newarray method */#define HEAP_TRACKER_native_newobj _newobj /* Name of java newobj native */#define HEAP_TRACKER_native_newarr _newarr /* Name of java newarray native */#define HEAP_TRACKER_engaged engaged /* Name of static field switch *//* C macros to create strings from tokens */#define _STRING(s) #s#define STRING(s) _STRING(s)/* ------------------------------------------------------------------- *//* Flavors of traces (to separate out stack traces) */typedef enum { TRACE_FIRST = 0, TRACE_USER = 0, TRACE_BEFORE_VM_START = 1, TRACE_BEFORE_VM_INIT = 2, TRACE_VM_OBJECT = 3, TRACE_MYSTERY = 4, TRACE_LAST = 4 } TraceFlavor;static char * flavorDesc[] = { "", "before VM_START", "before VM_INIT", "VM_OBJECT", "unknown"};/* Trace (Stack Trace) */#define MAX_FRAMES 6typedef struct Trace { /* Number of frames (includes HEAP_TRACKER methods) */ jint nframes; /* Frames from GetStackTrace() (2 extra for HEAP_TRACKER methods) */ jvmtiFrameInfo frames[MAX_FRAMES+2]; /* Used to make some traces unique */ TraceFlavor flavor;} Trace;/* Trace information (more than one object will have this as a tag) */typedef struct TraceInfo { /* Trace where this object was allocated from */ Trace trace; /* 64 bit hash code that attempts to identify this specific trace */ jlong hashCode; /* Total space taken up by objects allocated from this trace */ jlong totalSpace; /* Total count of objects ever allocated from this trace */ int totalCount; /* Total live objects that were allocated from this trace */ int useCount; /* The next TraceInfo in the hash bucket chain */ struct TraceInfo *next;} TraceInfo;/* Global agent data structure */typedef struct { /* JVMTI Environment */ jvmtiEnv *jvmti; /* State of the VM flags */ jboolean vmStarted; jboolean vmInitialized; jboolean vmDead; /* Options */ int maxDump; /* Data access Lock */ jrawMonitorID lock; /* Counter on classes where BCI has been applied */ jint ccount; /* Hash table to lookup TraceInfo's via Trace's */ #define HASH_INDEX_BIT_WIDTH 12 /* 4096 */ #define HASH_BUCKET_COUNT (1<<HASH_INDEX_BIT_WIDTH) #define HASH_INDEX_MASK (HASH_BUCKET_COUNT-1) TraceInfo *hashBuckets[HASH_BUCKET_COUNT]; /* Count of TraceInfo's allocated */ int traceInfoCount; /* Pre-defined traces for the system and mystery situations */ TraceInfo *emptyTrace[TRACE_LAST+1];} GlobalAgentData;static GlobalAgentData *gdata;/* Enter a critical section by doing a JVMTI Raw Monitor Enter */static voidenterCriticalSection(jvmtiEnv *jvmti){ jvmtiError error; error = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock); check_jvmti_error(jvmti, error, "Cannot enter with raw monitor");}/* Exit a critical section by doing a JVMTI Raw Monitor Exit */static voidexitCriticalSection(jvmtiEnv *jvmti){ jvmtiError error; error = (*jvmti)->RawMonitorExit(jvmti, gdata->lock); check_jvmti_error(jvmti, error, "Cannot exit with raw monitor");}/* Update stats on a TraceInfo */static TraceInfo *updateStats(TraceInfo *tinfo){ tinfo->totalCount++; tinfo->useCount++; return tinfo;}/* Get TraceInfo for empty stack */static TraceInfo *emptyTrace(TraceFlavor flavor){ return updateStats(gdata->emptyTrace[flavor]);}/* Allocate new TraceInfo */static TraceInfo *newTraceInfo(Trace *trace, jlong hashCode, TraceFlavor flavor){ TraceInfo *tinfo; tinfo = (TraceInfo*)calloc(1, sizeof(TraceInfo)); if ( tinfo == NULL ) { fatal_error("ERROR: Ran out of malloc() space\n"); } else { int hashIndex; tinfo->trace = *trace; tinfo->trace.flavor = flavor; tinfo->hashCode = hashCode; gdata->traceInfoCount++; hashIndex = (int)(hashCode & HASH_INDEX_MASK); tinfo->next = gdata->hashBuckets[hashIndex]; gdata->hashBuckets[hashIndex] = tinfo; } return tinfo;}/* Create hash code for a Trace */static jlonghashTrace(Trace *trace){ jlong hashCode; int i; hashCode = 0; for ( i = 0 ; i < trace->nframes ; i++ ) { hashCode = (hashCode << 3) + (jlong)(ptrdiff_t)(void*)(trace->frames[i].method); hashCode = (hashCode << 2) + (jlong)(trace->frames[i].location); } hashCode = (hashCode << 3) + trace->nframes; hashCode += trace->flavor; return hashCode;}/* 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;}/* Get TraceInfo for this allocation */static TraceInfo *findTraceInfo(jvmtiEnv *jvmti, jthread thread, TraceFlavor flavor){ TraceInfo *tinfo; jvmtiError error; tinfo = NULL; if ( thread != NULL ) { static Trace empty; Trace trace; /* Before VM_INIT thread could be NULL, watch out */ trace = empty; error = (*jvmti)->GetStackTrace(jvmti, thread, 0, MAX_FRAMES+2, trace.frames, &(trace.nframes)); /* If we get a PHASE error, the VM isn't ready, or it died */ if ( error == JVMTI_ERROR_WRONG_PHASE ) { /* It is assumed this is before VM_INIT */ if ( flavor == TRACE_USER ) { tinfo = emptyTrace(TRACE_BEFORE_VM_INIT); } else { tinfo = emptyTrace(flavor); } } else { check_jvmti_error(jvmti, error, "Cannot get stack trace"); /* Lookup this entry */ tinfo = lookupOrEnter(jvmti, &trace, flavor); } } else { /* If thread==NULL, it's assumed this is before VM_START */ if ( flavor == TRACE_USER ) { tinfo = emptyTrace(TRACE_BEFORE_VM_START); } else { tinfo = emptyTrace(flavor); } } return tinfo;}/* Tag an object with a TraceInfo pointer. */static voidtagObjectWithTraceInfo(jvmtiEnv *jvmti, jobject object, TraceInfo *tinfo){ jvmtiError error;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?