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