Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/demo/jvmti/heapViewer/heapViewer.c
38827 views
/*1* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940#include <stdio.h>41#include <stddef.h>42#include <stdlib.h>43#include <string.h>4445#include "jni.h"46#include "jvmti.h"4748#include "agent_util.h"4950/* Global static data */51typedef struct {52jboolean vmDeathCalled;53jboolean dumpInProgress;54jrawMonitorID lock;55} GlobalData;56static GlobalData globalData, *gdata = &globalData;5758/* Typedef to hold class details */59typedef struct {60char *signature;61int count;62int space;63} ClassDetails;6465/* Enter agent monitor protected section */66static void67enterAgentMonitor(jvmtiEnv *jvmti)68{69jvmtiError err;7071err = (*jvmti)->RawMonitorEnter(jvmti, gdata->lock);72check_jvmti_error(jvmti, err, "raw monitor enter");73}7475/* Exit agent monitor protected section */76static void77exitAgentMonitor(jvmtiEnv *jvmti)78{79jvmtiError err;8081err = (*jvmti)->RawMonitorExit(jvmti, gdata->lock);82check_jvmti_error(jvmti, err, "raw monitor exit");83}8485/* Heap object callback */86static jint JNICALL87cbHeapObject(jlong class_tag, jlong size, jlong* tag_ptr, jint length,88void* user_data)89{90if ( class_tag != (jlong)0 ) {91ClassDetails *d;9293d = (ClassDetails*)(void*)(ptrdiff_t)class_tag;94(*((jint*)(user_data)))++;95d->count++;96d->space += (int)size;97}98return JVMTI_VISIT_OBJECTS;99}100101/* Compare two ClassDetails */102static int103compareDetails(const void *p1, const void *p2)104{105return ((ClassDetails*)p2)->space - ((ClassDetails*)p1)->space;106}107108/* Callback for JVMTI_EVENT_DATA_DUMP_REQUEST (Ctrl-\ or at exit) */109static void JNICALL110dataDumpRequest(jvmtiEnv *jvmti)111{112enterAgentMonitor(jvmti); {113if ( !gdata->vmDeathCalled && !gdata->dumpInProgress ) {114jvmtiHeapCallbacks heapCallbacks;115ClassDetails *details;116jvmtiError err;117jclass *classes;118jint totalCount;119jint count;120jint i;121122gdata->dumpInProgress = JNI_TRUE;123124/* Get all the loaded classes */125err = (*jvmti)->GetLoadedClasses(jvmti, &count, &classes);126check_jvmti_error(jvmti, err, "get loaded classes");127128/* Setup an area to hold details about these classes */129details = (ClassDetails*)calloc(sizeof(ClassDetails), count);130if ( details == NULL ) {131fatal_error("ERROR: Ran out of malloc space\n");132}133for ( i = 0 ; i < count ; i++ ) {134char *sig;135136/* Get and save the class signature */137err = (*jvmti)->GetClassSignature(jvmti, classes[i], &sig, NULL);138check_jvmti_error(jvmti, err, "get class signature");139if ( sig == NULL ) {140fatal_error("ERROR: No class signature found\n");141}142details[i].signature = strdup(sig);143deallocate(jvmti, sig);144145/* Tag this jclass */146err = (*jvmti)->SetTag(jvmti, classes[i],147(jlong)(ptrdiff_t)(void*)(&details[i]));148check_jvmti_error(jvmti, err, "set object tag");149}150151/* Iterate through the heap and count up uses of jclass */152(void)memset(&heapCallbacks, 0, sizeof(heapCallbacks));153heapCallbacks.heap_iteration_callback = &cbHeapObject;154totalCount = 0;155err = (*jvmti)->IterateThroughHeap(jvmti,156JVMTI_HEAP_FILTER_CLASS_UNTAGGED, NULL,157&heapCallbacks, (const void *)&totalCount);158check_jvmti_error(jvmti, err, "iterate through heap");159160/* Remove tags */161for ( i = 0 ; i < count ; i++ ) {162/* Un-Tag this jclass */163err = (*jvmti)->SetTag(jvmti, classes[i], (jlong)0);164check_jvmti_error(jvmti, err, "set object tag");165}166167/* Sort details by space used */168qsort(details, count, sizeof(ClassDetails), &compareDetails);169170/* Print out sorted table */171stdout_message("Heap View, Total of %d objects found.\n\n",172totalCount);173174stdout_message("Space Count Class Signature\n");175stdout_message("---------- ---------- ----------------------\n");176177for ( i = 0 ; i < count ; i++ ) {178if ( details[i].space == 0 || i > 20 ) {179break;180}181stdout_message("%10d %10d %s\n",182details[i].space, details[i].count, details[i].signature);183}184stdout_message("---------- ---------- ----------------------\n\n");185186/* Free up all allocated space */187deallocate(jvmti, classes);188for ( i = 0 ; i < count ; i++ ) {189if ( details[i].signature != NULL ) {190free(details[i].signature);191}192}193free(details);194195gdata->dumpInProgress = JNI_FALSE;196}197} exitAgentMonitor(jvmti);198}199200/* Callback for JVMTI_EVENT_VM_INIT */201static void JNICALL202vmInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)203{204enterAgentMonitor(jvmti); {205jvmtiError err;206207err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,208JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);209check_jvmti_error(jvmti, err, "set event notification");210} exitAgentMonitor(jvmti);211}212213/* Callback for JVMTI_EVENT_VM_DEATH */214static void JNICALL215vmDeath(jvmtiEnv *jvmti, JNIEnv *env)216{217jvmtiError err;218219/* Make sure everything has been garbage collected */220err = (*jvmti)->ForceGarbageCollection(jvmti);221check_jvmti_error(jvmti, err, "force garbage collection");222223/* Disable events and dump the heap information */224enterAgentMonitor(jvmti); {225err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_DISABLE,226JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);227check_jvmti_error(jvmti, err, "set event notification");228229dataDumpRequest(jvmti);230231gdata->vmDeathCalled = JNI_TRUE;232} exitAgentMonitor(jvmti);233}234235/* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */236JNIEXPORT jint JNICALL237Agent_OnLoad(JavaVM *vm, char *options, void *reserved)238{239jint rc;240jvmtiError err;241jvmtiCapabilities capabilities;242jvmtiEventCallbacks callbacks;243jvmtiEnv *jvmti;244245/* Get JVMTI environment */246jvmti = NULL;247rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);248if (rc != JNI_OK) {249fatal_error("ERROR: Unable to create jvmtiEnv, error=%d\n", rc);250return -1;251}252if ( jvmti == NULL ) {253fatal_error("ERROR: No jvmtiEnv* returned from GetEnv\n");254}255256/* Get/Add JVMTI capabilities */257(void)memset(&capabilities, 0, sizeof(capabilities));258capabilities.can_tag_objects = 1;259capabilities.can_generate_garbage_collection_events = 1;260err = (*jvmti)->AddCapabilities(jvmti, &capabilities);261check_jvmti_error(jvmti, err, "add capabilities");262263/* Create the raw monitor */264err = (*jvmti)->CreateRawMonitor(jvmti, "agent lock", &(gdata->lock));265check_jvmti_error(jvmti, err, "create raw monitor");266267/* Set callbacks and enable event notifications */268memset(&callbacks, 0, sizeof(callbacks));269callbacks.VMInit = &vmInit;270callbacks.VMDeath = &vmDeath;271callbacks.DataDumpRequest = &dataDumpRequest;272err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));273check_jvmti_error(jvmti, err, "set event callbacks");274err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,275JVMTI_EVENT_VM_INIT, NULL);276check_jvmti_error(jvmti, err, "set event notifications");277err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,278JVMTI_EVENT_VM_DEATH, NULL);279check_jvmti_error(jvmti, err, "set event notifications");280return 0;281}282283/* Agent_OnUnload() is called last */284JNIEXPORT void JNICALL285Agent_OnUnload(JavaVM *vm)286{287}288289290