management.cpp revision 1677
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_management.cpp.incl"
void management_init() {
Management::init();
ThreadService::init();
RuntimeService::init();
}
void Management::init() {
// These counters are for java.lang.management API support.
// They are created even if -XX:-UsePerfData is set and in
// that case, they will be allocated on C heap.
// Initialize optional support
if (os::is_thread_cpu_time_supported()) {
} else {
}
#ifndef SERVICES_KERNEL
// This depends on the heap inspector
#endif // SERVICES_KERNEL
}
// Start the low memory detector thread
if (ManagementServer) {
// Load and initialize the sun.management.Agent class
// invoke startAgent method to start the management server
Handle(),
true,
CHECK);
ik,
CHECK);
}
}
}
if (ik->should_be_initialized()) {
}
return ik();
}
// if the performance counter is not initialized,
// then vm initialization failed; simply return.
if (_begin_vm_creation_time == NULL) return;
PerfMemory::set_accessible(true);
}
TimeStamp t;
t.update();
}
MemoryService::oops_do(f);
ThreadService::oops_do(f);
}
if (_threadInfo_klass == NULL) {
_threadInfo_klass = load_and_initialize_klass(vmSymbolHandles::java_lang_management_ThreadInfo(), CHECK_NULL);
}
return _threadInfo_klass;
}
if (_memoryUsage_klass == NULL) {
_memoryUsage_klass = load_and_initialize_klass(vmSymbolHandles::java_lang_management_MemoryUsage(), CHECK_NULL);
}
return _memoryUsage_klass;
}
if (_memoryPoolMXBean_klass == NULL) {
_memoryPoolMXBean_klass = load_and_initialize_klass(vmSymbolHandles::java_lang_management_MemoryPoolMXBean(), CHECK_NULL);
}
return _memoryPoolMXBean_klass;
}
if (_memoryManagerMXBean_klass == NULL) {
_memoryManagerMXBean_klass = load_and_initialize_klass(vmSymbolHandles::java_lang_management_MemoryManagerMXBean(), CHECK_NULL);
}
return _memoryManagerMXBean_klass;
}
if (_garbageCollectorMXBean_klass == NULL) {
_garbageCollectorMXBean_klass = load_and_initialize_klass(vmSymbolHandles::java_lang_management_GarbageCollectorMXBean(), CHECK_NULL);
}
return _garbageCollectorMXBean_klass;
}
if (_sensor_klass == NULL) {
}
return _sensor_klass;
}
if (_managementFactory_klass == NULL) {
_managementFactory_klass = load_and_initialize_klass(vmSymbolHandles::sun_management_ManagementFactory(), CHECK_NULL);
}
return _managementFactory_klass;
}
static void initialize_ThreadInfo_constructor_arguments(JavaCallArguments* args, ThreadSnapshot* snapshot, TRAPS) {
if (ThreadService::is_thread_monitoring_contention()) {
} else {
// set them to -1 if thread contention monitoring is disabled.
}
assert((thread_status & JMM_THREAD_STATE_FLAG_MASK) == 0, "Flags already set in thread_status in Thread object");
if (snapshot->is_ext_suspended()) {
}
if (snapshot->is_in_native()) {
}
} else {
stacktrace_h = Handle();
}
}
// Helper function to construct a ThreadInfo object
// First allocate a ThreadObj object and
// push the receiver as the first argument
// initialize the arguments for the ThreadInfo constructor
// Call ThreadInfo constructor with no locked monitors and synchronizers
ik,
&args,
return (instanceOop) element();
}
TRAPS) {
// First allocate a ThreadObj object and
// push the receiver as the first argument
// initialize the arguments for the ThreadInfo constructor
// push the locked monitors and synchronizers in the arguments
// Call ThreadInfo constructor with locked monitors and synchronizers
ik,
&args,
return (instanceOop) element();
}
// Helper functions
// Sequential search for now. Need to do better optimization later.
if (!thread->is_exiting() &&
break;
}
}
return java_thread;
}
}
if (!h->is_a(k)) {
"the object is not an instance of java.lang.management.GarbageCollectorMXBean class",
NULL);
}
"Invalid GC memory manager",
NULL);
}
return (GCMemoryManager*) gc;
}
}
}
// should be non-empty array
if (num_threads == 0) {
"Empty array of thread IDs");
}
// Validate input thread IDs
int i = 0;
for (i = 0; i < num_threads; i++) {
if (tid <= 0) {
// throw exception if invalid thread id.
"Invalid thread ID entry");
}
}
}
// check if the element of infoArray is of type ThreadInfo class
if (element_klass != threadinfo_klass) {
"infoArray element type is not ThreadInfo class");
}
}
}
}
// Returns a version string and sets major and minor version if
// the input parameters are non-null.
return JMM_VERSION;
// Gets the list of VM monitoring and management optional supports
// Returns 0 if succeeded; otherwise returns non-zero.
return -1;
}
return 0;
// Returns a java.lang.String object containing the input arguments to the VM.
return NULL;
}
int i;
for (i = 0; i < num_flags; i++) {
}
for (i = 0; i < num_args; i++) {
}
// add a space between each argument
// Return the list of input arguments passed to the VM
// and preserve the order that the VM processes.
args[0] = '\0';
// concatenate all jvm_flags
if (num_flags > 0) {
for (i = 1; i < num_flags; i++) {
}
}
// append a space if args already contains one or more jvm_flags
}
// concatenate all jvm_args
if (num_args > 0) {
for (i = 1; i < num_args; i++) {
}
}
// Returns an array of java.lang.String object containing the input arguments to the VM.
return NULL;
}
int index = 0;
}
}
// Returns an array of java/lang/management/MemoryPoolMXBean object
// one for each memory pool if obj == null; otherwise returns
// an array of memory pools for a given memory manager if
// it is a valid memory manager.
int num_memory_pools;
} else {
return NULL;
}
}
// Allocate the resulting MemoryPoolMXBean[] object
// Get all memory pools
for (int i = 0; i < num_memory_pools; i++) {
}
} else {
// Get memory pools managed by a given memory manager
for (int i = 0; i < num_memory_pools; i++) {
}
}
// Returns an array of java/lang/management/MemoryManagerMXBean object
// one for each memory manager if obj == null; otherwise returns
// an array of memory managers for a given memory pool if
// it is a valid memory pool.
int num_mgrs;
} else {
return NULL;
}
}
// Allocate the resulting MemoryManagerMXBean[] object
// Get all memory managers
for (int i = 0; i < num_mgrs; i++) {
}
} else {
// Get memory managers for a given memory pool
for (int i = 0; i < num_mgrs; i++) {
}
}
// Returns a java/lang/management/MemoryUsage object containing the memory usage
// of a given memory pool.
} else {
return NULL;
}
// Returns a java/lang/management/MemoryUsage object containing the memory usage
// of a given memory pool.
} else {
return NULL;
}
// Returns a java/lang/management/MemoryUsage object containing the memory usage
// of a given memory pool after most recent GC.
} else {
return NULL;
}
// Sets the memory pool sensor for a threshold type
JVM_ENTRY(void, jmm_SetPoolSensor(JNIEnv* env, jobject obj, jmmThresholdType type, jobject sensorObj))
}
"Sensor is not an instance of sun.management.Sensor class");
}
switch (type) {
case JMM_USAGE_THRESHOLD_HIGH:
case JMM_USAGE_THRESHOLD_LOW:
// have only one sensor for threshold high and low
break;
// have only one sensor for threshold high and low
break;
default:
assert(false, "Unrecognized type");
}
// Sets the threshold of a given memory pool.
// Returns the previous threshold.
//
// Input parameters:
// pool - the MemoryPoolMXBean object
// type - threshold type
// threshold - the new threshold (must not be negative)
//
JVM_ENTRY(jlong, jmm_SetPoolThreshold(JNIEnv* env, jobject obj, jmmThresholdType type, jlong threshold))
if (threshold < 0) {
"Invalid threshold value",
-1);
}
st.print("Invalid valid threshold value. Threshold value (" UINT64_FORMAT ") > max value of size_t (" SIZE_FORMAT ")", (size_t)threshold, max_uintx);
}
switch (type) {
case JMM_USAGE_THRESHOLD_HIGH:
return -1;
}
break;
case JMM_USAGE_THRESHOLD_LOW:
return -1;
}
break;
return -1;
}
// return and the new threshold is effective for the next GC
return -1;
}
// return and the new threshold is effective for the next GC
default:
assert(false, "Unrecognized type");
return -1;
}
// When the threshold is changed, reevaluate if the low memory
// detection is enabled.
}
return prev;
// Returns a java/lang/management/MemoryUsage object representing
// the memory usage for the heap or non-heap memory.
// Calculate the memory usage
size_t total_init = 0;
size_t total_used = 0;
size_t total_committed = 0;
bool has_undefined_init_size = false;
bool has_undefined_max_size = false;
for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
total_used += u.used();
total_committed += u.committed();
// if any one of the memory pool has undefined init_size or max_size,
// set it to -1
has_undefined_init_size = true;
}
if (!has_undefined_init_size) {
total_init += u.init_size();
}
has_undefined_max_size = true;
}
if (!has_undefined_max_size) {
}
}
}
// In our current implementation, we make sure that all non-heap
// pools have defined init and max sizes. Heap pools do not matter,
// as we never use total_init and total_max for them.
// Returns the boolean value of a given attribute.
switch (att) {
case JMM_VERBOSE_GC:
return MemoryService::get_verbose();
case JMM_VERBOSE_CLASS:
return ClassLoadingService::get_verbose();
return ThreadService::is_thread_monitoring_contention();
case JMM_THREAD_CPU_TIME:
return ThreadService::is_thread_cpu_time_enabled();
default:
assert(0, "Unrecognized attribute");
return false;
}
// Sets the given boolean attribute and returns the previous value.
switch (att) {
case JMM_VERBOSE_GC:
case JMM_VERBOSE_CLASS:
case JMM_THREAD_CPU_TIME:
default:
assert(0, "Unrecognized attribute");
return false;
}
switch (att) {
case JMM_GC_TIME_MS:
return mgr->gc_time_ms();
case JMM_GC_COUNT:
// current implementation only has 1 ext attribute
return 1;
default:
assert(0, "Unrecognized GC attribute");
return -1;
}
}
class VmThreadCountClosure: public ThreadClosure {
private:
int _count;
public:
VmThreadCountClosure() : _count(0) {};
};
// exclude externally visible JavaThreads
return;
}
_count++;
}
static jint get_vm_thread_count() {
{
}
}
static jint get_num_flags() {
// last flag entry is always NULL, so subtract 1
int count = 0;
for (int i = 0; i < nFlags; i++) {
// Exclude the locked (diagnostic, experimental) flags
count++;
}
}
return count;
}
switch (att) {
case JMM_CLASS_LOADED_COUNT:
return ClassLoadingService::loaded_class_count();
case JMM_CLASS_UNLOADED_COUNT:
return ClassLoadingService::unloaded_class_count();
case JMM_THREAD_TOTAL_COUNT:
return ThreadService::get_total_thread_count();
case JMM_THREAD_LIVE_COUNT:
return ThreadService::get_live_thread_count();
case JMM_THREAD_PEAK_COUNT:
return ThreadService::get_peak_thread_count();
case JMM_THREAD_DAEMON_COUNT:
return ThreadService::get_daemon_thread_count();
return Management::vm_init_done_time();
case JMM_OS_PROCESS_ID:
return os::current_process_id();
// Hotspot-specific counters
case JMM_CLASS_LOADED_BYTES:
return ClassLoadingService::loaded_class_bytes();
case JMM_CLASS_UNLOADED_BYTES:
return ClassLoadingService::unloaded_class_bytes();
return ClassLoadingService::loaded_shared_class_count();
return ClassLoadingService::unloaded_shared_class_count();
return ClassLoadingService::loaded_shared_class_bytes();
return ClassLoadingService::unloaded_shared_class_bytes();
return ClassLoader::classloader_time_ms();
case JMM_VM_GLOBAL_COUNT:
return get_num_flags();
case JMM_SAFEPOINT_COUNT:
return RuntimeService::safepoint_count();
return RuntimeService::safepoint_sync_time_ms();
return RuntimeService::safepoint_time_ms();
case JMM_TOTAL_APP_TIME_MS:
return RuntimeService::application_time_ms();
case JMM_VM_THREAD_COUNT:
return get_vm_thread_count();
return ClassLoader::class_init_count();
return ClassLoader::class_init_time_ms();
return ClassLoader::class_verify_time_ms();
return ClassLoadingService::class_method_data_size();
return os::physical_memory();
default:
return -1;
}
}
// Returns the long value of a given attribute.
return get_long_attribute(att);
} else {
}
}
return -1;
// Gets the value of all attributes specified in the given array
// and sets the value in the result array.
// Returns the number of attributes found.
int num_atts = 0;
for (int i = 0; i < count; i++) {
if (result[i] != -1) {
num_atts++;
}
}
} else {
for (int i = 0; i < count; i++) {
if (result[i] != -1) {
num_atts++;
}
}
}
return num_atts;
// Helper function to do thread dump for a specific list of threads
int num_threads,
int max_depth,
bool with_locked_monitors,
TRAPS) {
// First get an array of threadObj handles.
// A JavaThread may terminate before we get the stack trace.
GrowableArray<instanceHandle>* thread_handle_array = new GrowableArray<instanceHandle>(num_threads);
{
for (int i = 0; i < num_threads; i++) {
}
}
// Obtain thread dumps and thread snapshot information
max_depth, /* stack depth */
}
// Gets an array of ThreadInfo objects. Each element is the ThreadInfo
// for the thread ID specified in the corresponding entry in
// the given array of thread IDs; or NULL if the thread does not exist
// or has terminated.
//
// Input parameters:
// ids - array of thread IDs
// maxDepth - the maximum depth of stack traces to be dumped:
// maxDepth == -1 requests to dump entire stack trace.
// maxDepth == 0 requests no stack trace.
// infoArray - array of ThreadInfo objects
//
JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jobjectArray infoArray))
// Check if threads is null
}
if (maxDepth < -1) {
"Invalid maxDepth", -1);
}
// validate the thread id array
// validate the ThreadInfo[] parameters
// infoArray must be of the same length as the given array of thread IDs
"The length of the given ThreadInfo array does not match the length of the given array of thread IDs", -1);
}
if (JDK_Version::is_gte_jdk16x_version()) {
// make sure the AbstractOwnableSynchronizer klass is loaded before taking thread snapshots
}
// Must use ThreadDumpResult to store the ThreadSnapshot.
// GC may occur after the thread snapshots are taken but before
// this function returns. The threadObj and other oops kept
// in the ThreadSnapshot are marked and adjusted during GC.
if (maxDepth == 0) {
// no stack trace dumped - do not need to stop the world
{
for (int i = 0; i < num_threads; i++) {
// if the thread does not exist or now it is terminated,
// create dummy snapshot
ts = new ThreadSnapshot();
} else {
}
}
}
} else {
// obtain thread dump with the specific list of threads with stack trace
false, /* no locked monitor */
false, /* no locked synchronizers */
CHECK_0);
}
int index = 0;
// For each thread, create an java/lang/management/ThreadInfo object
// and fill with the thread information
// if the thread does not exist or now it is terminated, set threadinfo to NULL
continue;
}
// Create java.lang.management.ThreadInfo object
}
return 0;
// Dump thread info for the specified threads.
// It returns an array of ThreadInfo objects. Each element is the ThreadInfo
// for the thread ID specified in the corresponding entry in
// the given array of thread IDs; or NULL if the thread does not exist
// or has terminated.
//
// Input parameter:
// ids - array of thread IDs; NULL indicates all live threads
// locked_monitors - if true, dump locked object monitors
// locked_synchronizers - if true, dump locked JSR-166 synchronizers
//
JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors, jboolean locked_synchronizers))
if (JDK_Version::is_gte_jdk16x_version()) {
// make sure the AbstractOwnableSynchronizer klass is loaded before taking thread snapshots
}
// validate the thread id array
// obtain thread dump of a specific list of threads
-1, /* entire stack */
(locked_monitors ? true : false), /* with locked monitors */
(locked_synchronizers ? true : false), /* with locked synchronizers */
} else {
// obtain thread dump of all threads
-1, /* entire stack */
(locked_monitors ? true : false), /* with locked monitors */
(locked_synchronizers ? true : false) /* with locked synchronizers */);
}
// create the result ThreadInfo[] object
int index = 0;
// if the thread does not exist or now it is terminated, set threadinfo to NULL
continue;
}
// Create Object[] filled with locked monitors
// Create int[] filled with the stack depth where a monitor was locked
// Count the total number of locked monitors
for (int i = 0; i < num_frames; i++) {
}
if (locked_monitors) {
// Constructs Object[] and int[] to contain the object monitor and the stack depth
// where the thread locked it
monitors_array = mh;
depths_array = dh;
int count = 0;
int j = 0;
for (j = 0; j < len; j++) {
count++;
}
}
for (j = 0; j < jni_locked_monitors->length(); j++) {
// Monitor locked via JNI MonitorEnter call doesn't have stack depth info
count++;
}
}
if (locked_synchronizers) {
// Create Object[] filled with locked JSR-166 synchronizers
for (int k = 0; k < num_locked_synchronizers; k++) {
}
}
// Create java.lang.management.ThreadInfo object
}
// Returns an array of Class objects.
for (int i = 0; i < num_classes; i++) {
}
// Reset statistic. Return true if the requested statistic is reset.
// Otherwise, return false.
//
// Input parameters:
// obj - specify which instance the statistic associated with to be reset
// For PEAK_POOL_USAGE stat, obj is required to be a memory pool object.
// For THREAD_CONTENTION_COUNT and TIME stat, obj is required to be a thread ID.
// type - the type of statistic to be reset
//
switch (type) {
return true;
case JMM_STAT_THREAD_CONTENTION_TIME: {
if (tid < 0) {
}
// Look for the JavaThread of this given tid
if (tid == 0) {
// reset contention statistics for all threads if tid == 0
for (JavaThread* java_thread = Threads::first(); java_thread != NULL; java_thread = java_thread->next()) {
if (type == JMM_STAT_THREAD_CONTENTION_COUNT) {
} else {
}
}
} else {
// reset contention statistics for a given thread
if (java_thread == NULL) {
return false;
}
if (type == JMM_STAT_THREAD_CONTENTION_COUNT) {
} else {
}
}
return true;
break;
}
case JMM_STAT_PEAK_POOL_USAGE: {
if (o == NULL) {
}
return true;
}
break;
}
case JMM_STAT_GC_STAT: {
if (o == NULL) {
}
mgr->reset_gc_stat();
return true;
}
break;
}
default:
assert(0, "Unknown Statistic Type");
}
return false;
// Returns the fast estimate of CPU time consumed by
// a given thread (in nanoseconds).
// If thread_id == 0, return CPU time for the current thread.
if (!os::is_thread_cpu_time_supported()) {
return -1;
}
if (thread_id < 0) {
"Invalid thread ID", -1);
}
if (thread_id == 0) {
// current thread
return os::current_thread_cpu_time();
} else {
if (java_thread != NULL) {
}
}
return -1;
// Returns the CPU time consumed by a given thread (in nanoseconds).
// If thread_id == 0, CPU time for the current thread is returned.
// If user_sys_cpu_time = true, user level and system CPU time of
// a given thread is returned; otherwise, only user level CPU time
// is returned.
JVM_ENTRY(jlong, jmm_GetThreadCpuTimeWithKind(JNIEnv *env, jlong thread_id, jboolean user_sys_cpu_time))
if (!os::is_thread_cpu_time_supported()) {
return -1;
}
if (thread_id < 0) {
"Invalid thread ID", -1);
}
if (thread_id == 0) {
// current thread
} else {
if (java_thread != NULL) {
}
}
return -1;
// Returns a String array of all VM global flag names
// last flag entry is always NULL, so subtract 1
// allocate a temp array
int num_entries = 0;
for (int i = 0; i < nFlags; i++) {
// Exclude the locked (experimental, diagnostic) flags
num_entries++;
}
}
if (num_entries < nFlags) {
// Return array of right length
for(int i = 0; i < num_entries; i++) {
}
}
// Utility function used by jmm_GetVMGlobals. Returns false if flag type
// can't be determined, true otherwise. If false is returned, then *global
// will be incomplete and invalid.
} else {
}
} else if (flag->is_uint64_t()) {
} else {
return false;
}
case DEFAULT:
break;
case COMMAND_LINE:
break;
case ENVIRON_VAR:
break;
case CONFIG_FILE:
break;
case MANAGEMENT:
break;
case ERGONOMIC:
break;
default:
}
return true;
}
// Fill globals array of count length with jmmVMGlobal entries
// specified by names. If names == NULL, fill globals array
// with all Flags. Return value is number of entries
// created in globals.
// If a Flag with a given name in an array element does not
// exist, globals[i].name will be set to NULL.
}
// return the requested globals
// Make sure we have a String array
"Array element type is not String class", 0);
}
int num_entries = 0;
for (int i = 0; i < names_length && i < count; i++) {
if (s == NULL) {
}
num_entries++;
} else {
}
}
return num_entries;
} else {
// return all globals if names == NULL
// last flag entry is always NULL, so subtract 1
int num_entries = 0;
// Exclude the locked (diagnostic, experimental) flags
num_entries++;
}
}
return num_entries;
}
"The flag name cannot be null.");
}
"Flag does not exist.");
}
if (!flag->is_writeable()) {
"This flag is not writeable.");
}
bool succeed;
} else if (flag->is_uint64_t()) {
}
}
class ThreadTimesClosure: public ThreadClosure {
private:
int _names_len;
int _times_len;
int _count;
public:
};
_count = 0;
}
Handle s;
// exclude externally visible JavaThreads
return;
}
// skip if the result array is not big enough
return;
}
_count++;
}
// Fills names with VM internal thread names and times with the corresponding
// CPU times. If names or times is NULL, a NullPointerException is thrown.
// If the element type of names is not String, an IllegalArgumentException is
// thrown.
// If an array is not large enough to hold all the entries, only the entries
// that fit will be returned. Return value is the number of VM internal
// threads entries.
}
// Make sure we have a String array
"Array element type is not String class", 0);
}
{
}
// no deadlock found and return
return Handle();
}
int num_threads = 0;
}
int index = 0;
for (int i = 0; i < len; i++) {
index++;
}
}
return threads_ah;
}
// Finds cycles of threads that are deadlocked involved in object monitors
// and JSR-166 synchronizers.
// Returns an array of Thread objects which are in deadlock, if any.
// Otherwise, returns NULL.
//
// Input parameter:
// object_monitors_only - if true, only check object monitors
//
// Finds cycles of threads that are deadlocked on monitor locks
// Returns an array of Thread objects which are in deadlock, if any.
// Otherwise, returns NULL.
// Gets the information about GC extension attributes including
// the name of the attribute, its type, and a short description.
//
// Input parameters:
// mgr - GC memory manager
// info - caller allocated array of jmmExtAttributeInfo
// count - number of elements of the info array
//
// Returns the number of GC extension attributes filled in the info array; or
// -1 if info is not big enough
//
JVM_ENTRY(jint, jmm_GetGCExtAttributeInfo(JNIEnv *env, jobject mgr, jmmExtAttributeInfo* info, jint count))
// All GC memory managers have 1 attribute (number of GC threads)
if (count == 0) {
return 0;
}
}
return 1;
// verify the given array is an array of java/lang/management/MemoryUsage objects
// of a given length and return the objArrayOop
}
// array must be of the given length
"The length of the given MemoryUsage array does not match the number of memory pools.", 0);
}
// check if the element of array is of type MemoryUsage class
if (element_klass != usage_klass) {
"The element type is not MemoryUsage class", 0);
}
return array_h();
}
// Gets the statistics of the last GC of a given GC memory manager.
// Input parameters:
// obj - GarbageCollectorMXBean object
// gc_stat - caller allocated jmmGCStat where:
// a. before_gc_usage - array of MemoryUsage objects
// b. after_gc_usage - array of MemoryUsage objects
// c. gc_ext_attributes_values_size is set to the
// gc_ext_attribute_values array allocated
// d. gc_ext_attribute_values is a caller allocated array of jvalue.
//
// On return,
// gc_index == 0 indicates no GC statistics available
//
// before_gc_usage and after_gc_usage - filled with per memory pool
// before and after GC usage in the same order as the memory pools
// returned by GetMemoryPools for a given GC memory manager.
// num_gc_ext_attributes indicates the number of elements in
// the gc_ext_attribute_values array is filled; or
// -1 if the gc_ext_attributes_values array is not big enough
//
}
// Get the GCMemoryManager
// Make a copy of the last GC statistics
// GC may occur while constructing the last GC information
return;
}
// Current implementation does not have GC extension attributes
gc_stat->num_gc_ext_attributes = 0;
// Fill the arrays of MemoryUsage objects with before and after GC
// per pool memory usage
CHECK);
CHECK);
for (int i = 0; i < num_pools; i++) {
Handle before_usage = MemoryService::create_MemoryUsage_obj(stat->before_gc_usage_for_pool(i), CHECK);
// If max size == 0, this pool is a survivor space.
// Set max size = -1 since the pools will be swapped after GC.
} else {
}
}
if (gc_stat->gc_ext_attribute_values_size > 0) {
// Current implementation only has 1 attribute (number of GC threads)
// The type is 'I'
}
// Dump heap - Returns 0 if succeeds.
#ifndef SERVICES_KERNEL
"Output file name cannot be null.", -1);
}
"Output file name cannot be null.", -1);
}
}
return 0;
#else // SERVICES_KERNEL
return -1;
#endif // SERVICES_KERNEL
* (double)1000.0);
}
const struct jmmInterface_1_ jmm_interface = {
NULL,
NULL,
NULL,
NULL,
NULL,
};
if (version == JMM_VERSION_1_0) {
return (void*) &jmm_interface;
}
return NULL;
}