Hello
Thank you for your reply. I'll show the code that is giving me the "best" result. When I execute the code, all the events get executed, but you will see that even when it is in the middle of a dump, it still keeps sending the events. To fix this, i tried moving the call to dataDumpRequest() in line 213 a few lines up (i.e. when the raw monitor has been entered), but this causes the program to freeze. Then, in the actual dataDumpRequest() method, i put lines at the start and end to enter and exit the raw monitor, but this was causing the program to freeze too.
the include statements seem to have gone missing below. I am using stdio.h, stddef.h, stdlib.h and string.h
<pre>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "jvmti.h"
#include "jni.h"
static jvmtiEnv *jvmti;
static jrawMonitorID lock;
static int gc_count;
static int totalCount;
/* Typedef to hold class details */
typedef struct {
char *signature;
intcount;
intspace;
} ClassDetails;
/* Check for NULL pointer error */
#define CHECK_FOR_NULL(ptr) \
checkForNull(ptr, __FILE__, __LINE__)
static void checkForNull(void *ptr, char *file, int line)
{
if ( ptr == NULL ) {
fprintf(stderr, "ERROR: NULL pointer error in %s:%d\n", file, line);
abort();
}
}
/* Deallocate JVMTI memory */
static void deallocate(jvmtiEnv *jvmti, void *p)
{
jvmtiError err;
err = (*jvmti)->Deallocate(jvmti, (unsigned char *)p);
if ( err != JVMTI_ERROR_NONE ) {
fprintf(stderr, "ERROR: JVMTI Deallocate error err=%d\n", err);
abort();
}
}
/* Get name for JVMTI error code */
static char * getErrorName(jvmtiEnv *jvmti, jvmtiError errnum)
{
jvmtiError err;
char*name;
err = (*jvmti)->GetErrorName(jvmti, errnum, &name);
if ( err != JVMTI_ERROR_NONE ) {
fprintf(stderr, "ERROR: JVMTI GetErrorName error err=%d\n", err);
abort();
}
return name;
}
/* Check for JVMTI error */
#define CHECK_JVMTI_ERROR(jvmti, err) \
checkJvmtiError(jvmti, err, __FILE__, __LINE__)
static void checkJvmtiError(jvmtiEnv *jvmti, jvmtiError err, char *file, int line)
{
if ( err != JVMTI_ERROR_NONE ) {
char *name;
name = getErrorName(jvmti, err);
fprintf(stderr, "ERROR: JVMTI error err=%d(%s) in %s:%d\n",
err, name, file, line);
deallocate(jvmti, name);
abort();
}
}
/* Heap object callback */
static jvmtiIterationControl JNICALL heapObject(jlong class_tag, jlong size, jlong* tag_ptr, void* user_data)
{
if ( class_tag != (jlong)0 ) {
ClassDetails *d;
d = (ClassDetails*)(void*)(ptrdiff_t)class_tag;
totalCount++;
d->count++;
d->space += size;
}
return JVMTI_ITERATION_CONTINUE;
}
/* Compare two ClassDetails */
static int compareDetails(const void *p1, const void *p2)
{
return ((ClassDetails*)p2)->space - ((ClassDetails*)p1)->space;
}
static void dataDumpRequest()
{
// (*jvmti)->RawMonitorEnter(jvmti, lock);
{
jvmtiErrorerr;
void *user_data;
jclass*classes;
jint count;
jint i;
ClassDetails *details;
totalCount = 0;
/* Get all the loaded classes */
err = (*jvmti)->GetLoadedClasses(jvmti, &count, &classes);
CHECK_JVMTI_ERROR(jvmti, err);
/* Setup an area to hold details about these classes */
details = (ClassDetails*)calloc(sizeof(ClassDetails), count);
CHECK_FOR_NULL(details);
for ( i = 0 ; i < count ; i++ )
{
char *sig;
/* Get and save the class signature */
err = (*jvmti)->GetClassSignature(jvmti, classes, &sig, NULL);
CHECK_JVMTI_ERROR(jvmti, err);
CHECK_FOR_NULL(sig);
details.signature = strdup(sig);
deallocate(jvmti, sig);
/* Tag this jclass */
err = (*jvmti)->SetTag(jvmti, classes, (jlong)(ptrdiff_t)(void*)(&details));
CHECK_JVMTI_ERROR(jvmti, err);
}
/* Iterate over the heap and count up uses of jclass */
err = (*jvmti)->IterateOverHeap(jvmti, JVMTI_HEAP_OBJECT_EITHER, &heapObject, NULL);
CHECK_JVMTI_ERROR(jvmti, err);
/* Remove tags */
for ( i = 0 ; i < count ; i++ )
{
/* Un-Tag this jclass */
err = (*jvmti)->SetTag(jvmti, classes, (jlong)0);
CHECK_JVMTI_ERROR(jvmti, err);
}
/* Sort details by space used */
qsort(details, count, sizeof(ClassDetails), &compareDetails);
/* Print out sorted table */
fprintf(stdout, "Heap View, Total of %d objects found.\n\n", totalCount);
fprintf(stdout, "SpaceCountClass Signature\n");
fprintf(stdout, "- - -\n");
for ( i = 0 ; i < count ; i++ )
{
if ( details.space == 0 || i > 20 )
{
break;
}
fprintf(stdout, "%10d %10d %s\n",
details.space, details.count, details.signature);
}
fprintf(stdout, "- - -\n\n");
fflush(stdout);
/* Free up all allocated space */
deallocate(jvmti, classes);
for ( i = 0 ; i < count ; i++ )
{
if ( details.signature != NULL )
{
free(details.signature);
}
}
free(details);
}
// (*jvmti)->RawMonitorExit(jvmti, lock);
}
/* Worker thread that waits for garbage collections */
static void JNICALL worker2(jvmtiEnv* jvmti, JNIEnv* jni, void *p)
{
jvmtiErrorerr;
fprintf(stderr, "GC worker started...\n");
for (;;)
{
err = (*jvmti)->RawMonitorEnter(jvmti, lock);
if (err != JVMTI_ERROR_NONE)
{
fprintf(stderr, "ERROR: RawMonitorEnter failed, err=%d\n", err);
return;
}
while (gc_count == 0)
{
err = (*jvmti)->RawMonitorWait(jvmti, lock, 0);
if (err != JVMTI_ERROR_NONE)
{
fprintf(stderr, "ERROR: RawMonitorWait failed, err=%d\n", err);
err = (*jvmti)->RawMonitorExit(jvmti, lock);
CHECK_JVMTI_ERROR(jvmti, err);
return;
}
}
gc_count = 0;
err = (*jvmti)->RawMonitorExit(jvmti, lock);
CHECK_JVMTI_ERROR(jvmti, err);
dataDumpRequest();
/* Perform arbitrary JVMTI/JNI work here to do post-GC cleanup */
fprintf(stderr, "post-GarbageCollectionFinish actions...\n");
}
}
/* Creates a new jthread */
static jthread alloc_thread(JNIEnv *env)
{
jclassthrClass;
jmethodID cid;
jthreadres;
thrClass = (*env)->FindClass(env, "java/lang/Thread");
cid= (*env)->GetMethodID(env, thrClass, "<init>", "()V");
res= (*env)->NewObject(env, thrClass, cid);
return res;
}
static void JNICALL vmInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
{
jvmtiErrorerr;
err = (*jvmti)->RunAgentThread(jvmti, alloc_thread(env), &worker2, NULL,JVMTI_THREAD_MAX_PRIORITY);
CHECK_JVMTI_ERROR(jvmti, err);
fprintf(stderr, "VMInit...\n");
}
static void JNICALL gc_start(jvmtiEnv *jvmti_env)
{
jvmtiError err;
fprintf(stderr, "GarbageCollectionStart...\n");
}
static void JNICALL gc_finish(jvmtiEnv *jvmti_env)
{
jvmtiErrorerr;
fprintf(stderr, "GarbageCollectionFinish...\n");
err = (*jvmti)->RawMonitorEnter(jvmti, lock);
CHECK_JVMTI_ERROR(jvmti, err);
gc_count++;
err = (*jvmti)->RawMonitorNotify(jvmti, lock);
CHECK_JVMTI_ERROR(jvmti, err);
err = (*jvmti)->RawMonitorExit(jvmti, lock);
CHECK_JVMTI_ERROR(jvmti, err);
}
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
jint rc;
jvmtiCapabilities capa;
jvmtiEventCallbacks callbacks;
//get jvmti environment
rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
(*jvmti)->GetCapabilities(jvmti, &capa);
capa.can_tag_objects = 1;
capa.can_generate_garbage_collection_events = 1;
(*jvmti)->AddCapabilities(jvmti, &capa);
(*jvmti)->CreateRawMonitor(jvmti, "lock", &lock);
memset(&callbacks, 0, sizeof(callbacks));
callbacks.VMInit= &vmInit;
callbacks.GarbageCollectionStart = &gc_start;
callbacks.GarbageCollectionFinish = &gc_finish;
(*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
return JNI_OK;
}
</pre>