C:\hotspot-69087d08d473\src\share\vm/services/allocationSite.hpp
#ifndef SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
#define SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
#include "memory/allocation.hpp"
#include "utilities/nativeCallStack.hpp"
template <class E> class AllocationSite VALUE_OBJ_CLASS_SPEC {
private:
NativeCallStack _call_stack;
E e;
MEMFLAGS _flag;
public:
AllocationSite(const NativeCallStack& stack, MEMFLAGS flag) : _call_stack(stack), _flag(flag) { }
int hash() const { return _call_stack.hash(); }
bool equals(const NativeCallStack& stack) const {
return _call_stack.equals(stack);
}
bool equals(const AllocationSite<E>& other) const {
return other.equals(_call_stack);
}
const NativeCallStack* call_stack() const {
return &_call_stack;
}
E* data() { return &e; }
const E* peek() const { return &e; }
MEMFLAGS flag() const { return _flag; }
};
#endif // SHARE_VM_SERVICES_ALLOCATION_SITE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/attachListener.cpp
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "services/attachListener.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/heapDumper.hpp"
volatile bool AttachListener::_initialized;
static Klass* load_and_initialize_klass(Symbol* sh, TRAPS) {
Klass* k = SystemDictionary::resolve_or_fail(sh, true, CHECK_NULL);
instanceKlassHandle ik (THREAD, k);
if (ik->should_be_initialized()) {
ik->initialize(CHECK_NULL);
}
return ik();
}
static jint get_properties(AttachOperation* op, outputStream* out, Symbol* serializePropertiesMethod) {
Thread* THREAD = Thread::current();
HandleMark hm;
Symbol* klass = vmSymbols::sun_misc_VMSupport();
Klass* k = load_and_initialize_klass(klass, THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, out);
CLEAR_PENDING_EXCEPTION;
return JNI_ERR;
}
instanceKlassHandle ik(THREAD, k);
JavaValue result(T_OBJECT);
JavaCallArguments args;
Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature();
JavaCalls::call_static(&result,
ik,
serializePropertiesMethod,
signature,
&args,
THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, out);
CLEAR_PENDING_EXCEPTION;
return JNI_ERR;
}
oop res = (oop)result.get_jobject();
assert(res->is_typeArray(), "just checking");
assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
typeArrayOop ba = typeArrayOop(res);
jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
out->print_raw((const char*)addr, ba->length());
return JNI_OK;
}
static jint get_system_properties(AttachOperation* op, outputStream* out) {
return get_properties(op, out, vmSymbols::serializePropertiesToByteArray_name());
}
static jint get_agent_properties(AttachOperation* op, outputStream* out) {
return get_properties(op, out, vmSymbols::serializeAgentPropertiesToByteArray_name());
}
static jint data_dump(AttachOperation* op, outputStream* out) {
if (!ReduceSignalUsage) {
AttachListener::pd_data_dump();
} else {
if (JvmtiExport::should_post_data_dump()) {
JvmtiExport::post_data_dump();
}
}
return JNI_OK;
}
static jint thread_dump(AttachOperation* op, outputStream* out) {
bool print_concurrent_locks = false;
if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
print_concurrent_locks = true;
}
VM_PrintThreads op1(out, print_concurrent_locks);
VMThread::execute(&op1);
VM_PrintJNI op2(out);
VMThread::execute(&op2);
VM_FindDeadlocks op3(out);
VMThread::execute(&op3);
return JNI_OK;
}
static jint jcmd(AttachOperation* op, outputStream* out) {
Thread* THREAD = Thread::current();
DCmd::parse_and_execute(DCmd_Source_AttachAPI, out, op->arg(0), ' ', THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, out);
out->cr();
CLEAR_PENDING_EXCEPTION;
return JNI_ERR;
}
return JNI_OK;
}
jint dump_heap(AttachOperation* op, outputStream* out) {
const char* path = op->arg(0);
if (path == NULL || path[0] == '\0') {
out->print_cr("No dump file specified");
} else {
bool live_objects_only = true; // default is true to retain the behavior before this change is made
const char* arg1 = op->arg(1);
if (arg1 != NULL && (strlen(arg1) > 0)) {
if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) {
out->print_cr("Invalid argument to dumpheap operation: %s", arg1);
return JNI_ERR;
}
live_objects_only = strcmp(arg1, "-live") == 0;
}
HeapDumper dumper(live_objects_only /* request GC */);
int res = dumper.dump(op->arg(0));
if (res == 0) {
out->print_cr("Heap dump file created");
} else {
ResourceMark rm;
char* error = dumper.error_as_C_string();
if (error == NULL) {
out->print_cr("Dump failed - reason unknown");
} else {
out->print_cr("%s", error);
}
}
}
return JNI_OK;
}
static jint heap_inspection(AttachOperation* op, outputStream* out) {
bool live_objects_only = true; // default is true to retain the behavior before this change is made
const char* arg0 = op->arg(0);
if (arg0 != NULL && (strlen(arg0) > 0)) {
if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
return JNI_ERR;
}
live_objects_only = strcmp(arg0, "-live") == 0;
}
VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */);
VMThread::execute(&heapop);
return JNI_OK;
}
static jint set_bool_flag(const char* name, AttachOperation* op, outputStream* out) {
bool value = true;
const char* arg1;
if ((arg1 = op->arg(1)) != NULL) {
int tmp;
int n = sscanf(arg1, "%d", &tmp);
if (n != 1) {
out->print_cr("flag value must be a boolean (1 or 0)");
return JNI_ERR;
}
value = (tmp != 0);
}
bool res = CommandLineFlags::boolAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
if (! res) {
out->print_cr("setting flag %s failed", name);
}
return res? JNI_OK : JNI_ERR;
}
static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* out) {
intx value;
const char* arg1;
if ((arg1 = op->arg(1)) != NULL) {
int n = sscanf(arg1, INTX_FORMAT, &value);
if (n != 1) {
out->print_cr("flag value must be an integer");
return JNI_ERR;
}
}
bool res = CommandLineFlags::intxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
if (! res) {
out->print_cr("setting flag %s failed", name);
}
return res? JNI_OK : JNI_ERR;
}
static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
uintx value;
const char* arg1 = op->arg(1);
if (arg1 == NULL) {
out->print_cr("flag value must be specified");
return JNI_ERR;
}
int n = sscanf(arg1, UINTX_FORMAT, &value);
if (n != 1) {
out->print_cr("flag value must be an unsigned integer");
return JNI_ERR;
}
if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) {
FormatBuffer<80> err_msg("%s", "");
if (!Arguments::verify_MaxHeapFreeRatio(err_msg, value)) {
out->print_cr("%s", err_msg.buffer());
return JNI_ERR;
}
} else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) {
FormatBuffer<80> err_msg("%s", "");
if (!Arguments::verify_MinHeapFreeRatio(err_msg, value)) {
out->print_cr("%s", err_msg.buffer());
return JNI_ERR;
}
}
bool res = CommandLineFlags::uintxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
if (! res) {
out->print_cr("setting flag %s failed", name);
}
return res? JNI_OK : JNI_ERR;
}
static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
uint64_t value;
const char* arg1;
if ((arg1 = op->arg(1)) != NULL) {
int n = sscanf(arg1, UINT64_FORMAT, &value);
if (n != 1) {
out->print_cr("flag value must be an unsigned 64-bit integer");
return JNI_ERR;
}
}
bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
if (! res) {
out->print_cr("setting flag %s failed", name);
}
return res? JNI_OK : JNI_ERR;
}
static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
const char* value;
if ((value = op->arg(1)) == NULL) {
out->print_cr("flag value must be a string");
return JNI_ERR;
}
bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
if (res) {
FREE_C_HEAP_ARRAY(char, value, mtInternal);
} else {
out->print_cr("setting flag %s failed", name);
}
return res? JNI_OK : JNI_ERR;
}
static jint set_flag(AttachOperation* op, outputStream* out) {
const char* name = NULL;
if ((name = op->arg(0)) == NULL) {
out->print_cr("flag name is missing");
return JNI_ERR;
}
Flag* f = Flag::find_flag((char*)name, strlen(name));
if (f && f->is_external() && f->is_writeable()) {
if (f->is_bool()) {
return set_bool_flag(name, op, out);
} else if (f->is_intx()) {
return set_intx_flag(name, op, out);
} else if (f->is_uintx()) {
return set_uintx_flag(name, op, out);
} else if (f->is_uint64_t()) {
return set_uint64_t_flag(name, op, out);
} else if (f->is_ccstr()) {
return set_ccstr_flag(name, op, out);
} else {
ShouldNotReachHere();
return JNI_ERR;
}
} else {
return AttachListener::pd_set_flag(op, out);
}
}
static jint print_flag(AttachOperation* op, outputStream* out) {
const char* name = NULL;
if ((name = op->arg(0)) == NULL) {
out->print_cr("flag name is missing");
return JNI_ERR;
}
Flag* f = Flag::find_flag((char*)name, strlen(name));
if (f) {
f->print_as_flag(out);
out->cr();
} else {
out->print_cr("no such flag '%s'", name);
}
return JNI_OK;
}
static AttachOperationFunctionInfo funcs[] = {
{ "agentProperties", get_agent_properties },
{ "datadump", data_dump },
{ "dumpheap", dump_heap },
{ "load", JvmtiExport::load_agent_library },
{ "properties", get_system_properties },
{ "threaddump", thread_dump },
{ "inspectheap", heap_inspection },
{ "setflag", set_flag },
{ "printflag", print_flag },
{ "jcmd", jcmd },
{ NULL, NULL }
};
static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
os::set_priority(thread, NearMaxPriority);
thread->record_stack_base_and_size();
if (AttachListener::pd_init() != 0) {
return;
}
AttachListener::set_initialized();
for (;;) {
AttachOperation* op = AttachListener::dequeue();
if (op == NULL) {
return; // dequeue failed or shutdown
}
ResourceMark rm;
bufferedStream st;
jint res = JNI_OK;
if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
AttachListener::detachall();
} else {
AttachOperationFunctionInfo* info = NULL;
for (int i=0; funcs[i].name != NULL; i++) {
const char* name = funcs[i].name;
assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
if (strcmp(op->name(), name) == 0) {
info = &(funcs[i]);
break;
}
}
if (info == NULL) {
info = AttachListener::pd_find_operation(op->name());
}
if (info != NULL) {
res = (info->func)(op, &st);
} else {
st.print("Operation %s not recognized!", op->name());
res = JNI_ERR;
}
}
op->complete(res, &st);
}
}
bool AttachListener::has_init_error(TRAPS) {
if (HAS_PENDING_EXCEPTION) {
tty->print_cr("Exception in VM (AttachListener::init) : ");
java_lang_Throwable::print(PENDING_EXCEPTION, tty);
tty->cr();
CLEAR_PENDING_EXCEPTION;
return true;
} else {
return false;
}
}
void AttachListener::init() {
EXCEPTION_MARK;
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, THREAD);
if (has_init_error(THREAD)) {
return;
}
instanceKlassHandle klass (THREAD, k);
instanceHandle thread_oop = klass->allocate_instance_handle(THREAD);
if (has_init_error(THREAD)) {
return;
}
const char thread_name[] = "Attach Listener";
Handle string = java_lang_String::create_from_str(thread_name, THREAD);
if (has_init_error(THREAD)) {
return;
}
Handle thread_group (THREAD, Universe::system_thread_group());
JavaValue result(T_VOID);
JavaCalls::call_special(&result, thread_oop,
klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
THREAD);
if (has_init_error(THREAD)) {
return;
}
KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
JavaCalls::call_special(&result,
thread_group,
group,
vmSymbols::add_method_name(),
vmSymbols::thread_void_signature(),
thread_oop, // ARG 1
THREAD);
if (has_init_error(THREAD)) {
return;
}
{ MutexLocker mu(Threads_lock);
JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
if (listener_thread == NULL || listener_thread->osthread() == NULL) {
vm_exit_during_initialization("java.lang.OutOfMemoryError",
"unable to create new native thread");
}
java_lang_Thread::set_thread(thread_oop(), listener_thread);
java_lang_Thread::set_daemon(thread_oop());
listener_thread->set_threadObj(thread_oop());
Threads::add(listener_thread);
Thread::start(listener_thread);
}
}
void AttachListener::detachall() {
pd_detachall();
}
C:\hotspot-69087d08d473\src\share\vm/services/attachListener.hpp
#ifndef SHARE_VM_SERVICES_ATTACHLISTENER_HPP
#define SHARE_VM_SERVICES_ATTACHLISTENER_HPP
#include "memory/allocation.hpp"
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
class AttachOperation;
typedef jint (*AttachOperationFunction)(AttachOperation* op, outputStream* out);
struct AttachOperationFunctionInfo {
const char* name;
AttachOperationFunction func;
};
class AttachListener: AllStatic {
public:
static void vm_start() NOT_SERVICES_RETURN;
static void init() NOT_SERVICES_RETURN;
static void abort() NOT_SERVICES_RETURN;
static void detachall() NOT_SERVICES_RETURN;
static bool init_at_startup() NOT_SERVICES_RETURN_(false);
static bool is_init_trigger() NOT_SERVICES_RETURN_(false);
#if !INCLUDE_SERVICES
static bool is_attach_supported() { return false; }
#else
private:
static volatile bool _initialized;
public:
static bool is_initialized() { return _initialized; }
static void set_initialized() { _initialized = true; }
static bool is_attach_supported() { return !DisableAttachMechanism; }
static int pd_init();
static AttachOperationFunctionInfo* pd_find_operation(const char* name);
static jint pd_set_flag(AttachOperation* op, outputStream* out);
static void pd_detachall();
static void pd_data_dump();
static AttachOperation* dequeue();
#endif // !INCLUDE_SERVICES
private:
static bool has_init_error(TRAPS);
};
#if INCLUDE_SERVICES
class AttachOperation: public CHeapObj<mtInternal> {
public:
enum {
name_length_max = 16, // maximum length of name
arg_length_max = 1024, // maximum length of argument
arg_count_max = 3 // maximum number of arguments
};
static char* detachall_operation_name() { return (char*)"detachall"; }
private:
char _name[name_length_max+1];
char _arg[arg_count_max][arg_length_max+1];
public:
const char* name() const { return _name; }
void set_name(char* name) {
assert(strlen(name) <= name_length_max, "exceeds maximum name length");
strcpy(_name, name);
}
const char* arg(int i) const {
assert(i>=0 && i<arg_count_max, "invalid argument index");
return _arg[i];
}
void set_arg(int i, char* arg) {
assert(i>=0 && i<arg_count_max, "invalid argument index");
if (arg == NULL) {
_arg[i][0] = '\0';
} else {
assert(strlen(arg) <= arg_length_max, "exceeds maximum argument length");
strcpy(_arg[i], arg);
}
}
AttachOperation(char* name) {
set_name(name);
for (int i=0; i<arg_count_max; i++) {
set_arg(i, NULL);
}
}
virtual void complete(jint result, bufferedStream* result_stream) = 0;
};
#endif // INCLUDE_SERVICES
#endif // SHARE_VM_SERVICES_ATTACHLISTENER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/classLoadingService.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "memory/allocation.hpp"
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/classLoadingService.hpp"
#include "services/memoryService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
#ifdef DTRACE_ENABLED
#ifndef USDT2
HS_DTRACE_PROBE_DECL4(hotspot, class__loaded, char*, int, oop, bool);
HS_DTRACE_PROBE_DECL4(hotspot, class__unloaded, char*, int, oop, bool);
#define DTRACE_CLASSLOAD_PROBE(type, clss, shared) \
{ \
char* data = NULL; \
int len = 0; \
Symbol* name = (clss)->name(); \
if (name != NULL) { \
data = (char*)name->bytes(); \
len = name->utf8_length(); \
} \
HS_DTRACE_PROBE4(hotspot, class__##type, \
data, len, (void *)(clss)->class_loader(), (shared)); \
}
#else /* USDT2 */
#define HOTSPOT_CLASS_unloaded HOTSPOT_CLASS_UNLOADED
#define HOTSPOT_CLASS_loaded HOTSPOT_CLASS_LOADED
#define DTRACE_CLASSLOAD_PROBE(type, clss, shared) \
{ \
char* data = NULL; \
int len = 0; \
Symbol* name = (clss)->name(); \
if (name != NULL) { \
data = (char*)name->bytes(); \
len = name->utf8_length(); \
} \
HOTSPOT_CLASS_##type( /* type = unloaded, loaded */ \
data, len, (void *)(clss)->class_loader(), (shared)); \
}
#endif /* USDT2 */
#else // ndef DTRACE_ENABLED
#define DTRACE_CLASSLOAD_PROBE(type, clss, shared)
#endif
#if INCLUDE_MANAGEMENT
PerfCounter* ClassLoadingService::_classes_loaded_count = NULL;
PerfCounter* ClassLoadingService::_classes_unloaded_count = NULL;
PerfCounter* ClassLoadingService::_classbytes_loaded = NULL;
PerfCounter* ClassLoadingService::_classbytes_unloaded = NULL;
PerfCounter* ClassLoadingService::_shared_classes_loaded_count = NULL;
PerfCounter* ClassLoadingService::_shared_classes_unloaded_count = NULL;
PerfCounter* ClassLoadingService::_shared_classbytes_loaded = NULL;
PerfCounter* ClassLoadingService::_shared_classbytes_unloaded = NULL;
PerfVariable* ClassLoadingService::_class_methods_size = NULL;
void ClassLoadingService::init() {
EXCEPTION_MARK;
_classes_loaded_count =
PerfDataManager::create_counter(JAVA_CLS, "loadedClasses",
PerfData::U_Events, CHECK);
_classes_unloaded_count =
PerfDataManager::create_counter(JAVA_CLS, "unloadedClasses",
PerfData::U_Events, CHECK);
_shared_classes_loaded_count =
PerfDataManager::create_counter(JAVA_CLS, "sharedLoadedClasses",
PerfData::U_Events, CHECK);
_shared_classes_unloaded_count =
PerfDataManager::create_counter(JAVA_CLS, "sharedUnloadedClasses",
PerfData::U_Events, CHECK);
if (UsePerfData) {
_classbytes_loaded =
PerfDataManager::create_counter(SUN_CLS, "loadedBytes",
PerfData::U_Bytes, CHECK);
_classbytes_unloaded =
PerfDataManager::create_counter(SUN_CLS, "unloadedBytes",
PerfData::U_Bytes, CHECK);
_shared_classbytes_loaded =
PerfDataManager::create_counter(SUN_CLS, "sharedLoadedBytes",
PerfData::U_Bytes, CHECK);
_shared_classbytes_unloaded =
PerfDataManager::create_counter(SUN_CLS, "sharedUnloadedBytes",
PerfData::U_Bytes, CHECK);
_class_methods_size =
PerfDataManager::create_variable(SUN_CLS, "methodBytes",
PerfData::U_Bytes, CHECK);
}
}
void ClassLoadingService::notify_class_unloaded(InstanceKlass* k) {
DTRACE_CLASSLOAD_PROBE(unloaded, k, false);
_classes_unloaded_count->inc();
if (UsePerfData) {
size_t size = compute_class_size(k);
_classbytes_unloaded->inc(size);
Array<Method*>* methods = k->methods();
for (int i = 0; i < methods->length(); i++) {
_class_methods_size->inc(-methods->at(i)->size());
}
}
if (TraceClassUnloading) {
ResourceMark rm;
tty->print_cr("[Unloading class %s " INTPTR_FORMAT "]", k->external_name(), p2i(k));
}
}
void ClassLoadingService::notify_class_loaded(InstanceKlass* k, bool shared_class) {
DTRACE_CLASSLOAD_PROBE(loaded, k, shared_class);
PerfCounter* classes_counter = (shared_class ? _shared_classes_loaded_count
: _classes_loaded_count);
classes_counter->inc();
if (UsePerfData) {
PerfCounter* classbytes_counter = (shared_class ? _shared_classbytes_loaded
: _classbytes_loaded);
size_t size = compute_class_size(k);
classbytes_counter->inc(size);
}
}
size_t ClassLoadingService::compute_class_size(InstanceKlass* k) {
size_t class_size = 0;
class_size += k->size();
if (k->oop_is_instance()) {
class_size += k->methods()->size();
class_size += k->constants()->size();
class_size += k->local_interfaces()->size();
class_size += k->transitive_interfaces()->size();
}
return class_size * oopSize;
}
bool ClassLoadingService::set_verbose(bool verbose) {
MutexLocker m(Management_lock);
bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, Flag::MANAGEMENT);
assert(succeed, "Setting TraceClassLoading flag fails");
reset_trace_class_unloading();
return verbose;
}
void ClassLoadingService::reset_trace_class_unloading() {
assert(Management_lock->owned_by_self(), "Must own the Management_lock");
bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, Flag::MANAGEMENT);
assert(succeed, "Setting TraceClassUnLoading flag fails");
}
GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
Thread* LoadedClassesEnumerator::_current_thread = NULL;
LoadedClassesEnumerator::LoadedClassesEnumerator(Thread* cur_thread) {
assert(cur_thread == Thread::current(), "Check current thread");
int init_size = ClassLoadingService::loaded_class_count();
_klass_handle_array = new GrowableArray<KlassHandle>(init_size);
MutexLocker sd_mutex(SystemDictionary_lock);
_loaded_classes = _klass_handle_array;
_current_thread = cur_thread;
SystemDictionary::classes_do(&add_loaded_class);
}
#endif // INCLUDE_MANAGEMENT
C:\hotspot-69087d08d473\src\share\vm/services/classLoadingService.hpp
#ifndef SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
#define SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
#include "runtime/handles.hpp"
#include "runtime/perfData.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
class InstanceKlass;
class ClassLoadingService : public AllStatic {
private:
static PerfCounter* _classes_loaded_count;
static PerfCounter* _classes_unloaded_count;
static PerfCounter* _classbytes_loaded;
static PerfCounter* _classbytes_unloaded;
static PerfCounter* _shared_classes_loaded_count;
static PerfCounter* _shared_classes_unloaded_count;
static PerfCounter* _shared_classbytes_loaded;
static PerfCounter* _shared_classbytes_unloaded;
static PerfVariable* _class_methods_size;
static size_t compute_class_size(InstanceKlass* k);
public:
static void init();
static bool get_verbose() { return TraceClassLoading; }
static bool set_verbose(bool verbose);
static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN;
static jlong loaded_class_count() {
return _classes_loaded_count->get_value() + _shared_classes_loaded_count->get_value();
}
static jlong unloaded_class_count() {
return _classes_unloaded_count->get_value() + _shared_classes_unloaded_count->get_value();
}
static jlong loaded_class_bytes() {
if (UsePerfData) {
return _classbytes_loaded->get_value() + _shared_classbytes_loaded->get_value();
} else {
return -1;
}
}
static jlong unloaded_class_bytes() {
if (UsePerfData) {
return _classbytes_unloaded->get_value() + _shared_classbytes_unloaded->get_value();
} else {
return -1;
}
}
static jlong loaded_shared_class_count() {
return _shared_classes_loaded_count->get_value();
}
static jlong unloaded_shared_class_count() {
return _shared_classes_unloaded_count->get_value();
}
static jlong loaded_shared_class_bytes() {
if (UsePerfData) {
return _shared_classbytes_loaded->get_value();
} else {
return -1;
}
}
static jlong unloaded_shared_class_bytes() {
if (UsePerfData) {
return _shared_classbytes_unloaded->get_value();
} else {
return -1;
}
}
static jlong class_method_data_size() {
return (UsePerfData ? _class_methods_size->get_value() : -1);
}
static void notify_class_loaded(InstanceKlass* k, bool shared_class)
NOT_MANAGEMENT_RETURN;
static void notify_class_unloaded(InstanceKlass* k) NOT_MANAGEMENT_RETURN;
static void add_class_method_size(int size) {
#if INCLUDE_MANAGEMENT
if (UsePerfData) {
_class_methods_size->inc(size);
}
#endif // INCLUDE_MANAGEMENT
}
};
class LoadedClassesEnumerator : public StackObj {
private:
static GrowableArray<KlassHandle>* _loaded_classes;
static Thread* _current_thread;
GrowableArray<KlassHandle>* _klass_handle_array;
public:
LoadedClassesEnumerator(Thread* cur_thread);
int num_loaded_classes() { return _klass_handle_array->length(); }
KlassHandle get_klass(int index) { return _klass_handle_array->at(index); }
static void add_loaded_class(Klass* k) {
KlassHandle h(_current_thread, k);
_loaded_classes->append(h);
}
};
#endif // SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticArgument.cpp
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/thread.hpp"
#include "services/diagnosticArgument.hpp"
void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) {
if (is_set() && !allow_multiple()) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Duplicates in diagnostic command arguments\n");
}
parse_value(str, len, CHECK);
set_is_set(true);
}
void GenDCmdArgument::to_string(jlong l, char* buf, size_t len) {
jio_snprintf(buf, len, INT64_FORMAT, l);
}
void GenDCmdArgument::to_string(bool b, char* buf, size_t len) {
jio_snprintf(buf, len, b ? "true" : "false");
}
void GenDCmdArgument::to_string(NanoTimeArgument n, char* buf, size_t len) {
jio_snprintf(buf, len, INT64_FORMAT, n._nanotime);
}
void GenDCmdArgument::to_string(MemorySizeArgument m, char* buf, size_t len) {
jio_snprintf(buf, len, INT64_FORMAT, m._size);
}
void GenDCmdArgument::to_string(char* c, char* buf, size_t len) {
jio_snprintf(buf, len, "%s", (c != NULL) ? c : "");
}
void GenDCmdArgument::to_string(StringArrayArgument* f, char* buf, size_t len) {
int length = f->array()->length();
size_t written = 0;
buf[0] = 0;
for (int i = 0; i < length; i++) {
char* next_str = f->array()->at(i);
size_t next_size = strlen(next_str);
if (written + next_size > len) {
return;
}
strcat(buf, next_str);
written += next_size;
if (i < length-1 && len - written > 0) {
strcat(buf, ",");
}
}
}
template <> void DCmdArgument<jlong>::parse_value(const char* str,
size_t len, TRAPS) {
int scanned = -1;
if (str == NULL
|| sscanf(str, JLONG_FORMAT "%n", &_value, &scanned) != 1
|| (size_t)scanned != len)
{
ResourceMark rm;
char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
strncpy(buf, str, len);
buf[len] = '\0';
Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
"Integer parsing error in command argument '%s'. Could not parse: %s.", _name, buf);
}
}
template <> void DCmdArgument<jlong>::init_value(TRAPS) {
if (has_default()) {
this->parse_value(_default_string, strlen(_default_string), THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Default string must be parseable");
}
} else {
set_value(0);
}
}
template <> void DCmdArgument<jlong>::destroy_value() { }
template <> void DCmdArgument<bool>::parse_value(const char* str,
size_t len, TRAPS) {
if (len == 0) {
set_value(true);
} else {
if (len == strlen("true") && strncasecmp(str, "true", len) == 0) {
set_value(true);
} else if (len == strlen("false") && strncasecmp(str, "false", len) == 0) {
set_value(false);
} else {
ResourceMark rm;
char* buf = NEW_RESOURCE_ARRAY(char, len + 1);
strncpy(buf, str, len);
buf[len] = '\0';
Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
"Boolean parsing error in command argument '%s'. Could not parse: %s.", _name, buf);
}
}
}
template <> void DCmdArgument<bool>::init_value(TRAPS) {
if (has_default()) {
this->parse_value(_default_string, strlen(_default_string), THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Default string must be parsable");
}
} else {
set_value(false);
}
}
template <> void DCmdArgument<bool>::destroy_value() { }
template <> void DCmdArgument<char*>::parse_value(const char* str,
size_t len, TRAPS) {
if (str == NULL) {
_value = NULL;
} else {
_value = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
strncpy(_value, str, len);
_value[len] = 0;
}
}
template <> void DCmdArgument<char*>::init_value(TRAPS) {
if (has_default() && _default_string != NULL) {
this->parse_value(_default_string, strlen(_default_string), THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Default string must be parsable");
}
} else {
set_value(NULL);
}
}
template <> void DCmdArgument<char*>::destroy_value() {
if (_value != NULL) {
FREE_C_HEAP_ARRAY(char, _value, mtInternal);
set_value(NULL);
}
}
template <> void DCmdArgument<NanoTimeArgument>::parse_value(const char* str,
size_t len, TRAPS) {
if (str == NULL) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Integer parsing error nanotime value: syntax error, value is null");
}
int argc = sscanf(str, JLONG_FORMAT, &_value._time);
if (argc != 1) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Integer parsing error nanotime value: syntax error");
}
size_t idx = 0;
while(idx < len && isdigit(str[idx])) {
idx++;
}
if (idx == len) {
if (_value._time != 0) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Integer parsing error nanotime value: unit required");
} else {
_value._nanotime = 0;
strcpy(_value._unit, "ns");
return;
}
} else if(len - idx > 2) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Integer parsing error nanotime value: illegal unit");
} else {
strncpy(_value._unit, &str[idx], len - idx);
_value._unit[len-idx] = '\0';
}
if (strcmp(_value._unit, "ns") == 0) {
_value._nanotime = _value._time;
} else if (strcmp(_value._unit, "us") == 0) {
_value._nanotime = _value._time * 1000;
} else if (strcmp(_value._unit, "ms") == 0) {
_value._nanotime = _value._time * 1000 * 1000;
} else if (strcmp(_value._unit, "s") == 0) {
_value._nanotime = _value._time * 1000 * 1000 * 1000;
} else if (strcmp(_value._unit, "m") == 0) {
_value._nanotime = _value._time * 60 * 1000 * 1000 * 1000;
} else if (strcmp(_value._unit, "h") == 0) {
_value._nanotime = _value._time * 60 * 60 * 1000 * 1000 * 1000;
} else if (strcmp(_value._unit, "d") == 0) {
_value._nanotime = _value._time * 24 * 60 * 60 * 1000 * 1000 * 1000;
} else {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Integer parsing error nanotime value: illegal unit");
}
}
template <> void DCmdArgument<NanoTimeArgument>::init_value(TRAPS) {
if (has_default()) {
this->parse_value(_default_string, strlen(_default_string), THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Default string must be parsable");
}
} else {
_value._time = 0;
_value._nanotime = 0;
strcpy(_value._unit, "ns");
}
}
template <> void DCmdArgument<NanoTimeArgument>::destroy_value() { }
template <> void DCmdArgument<StringArrayArgument*>::parse_value(const char* str,
size_t len, TRAPS) {
_value->add(str,len);
}
template <> void DCmdArgument<StringArrayArgument*>::init_value(TRAPS) {
_value = new StringArrayArgument();
_allow_multiple = true;
if (has_default()) {
fatal("StringArrayArgument cannot have default value");
}
}
template <> void DCmdArgument<StringArrayArgument*>::destroy_value() {
if (_value != NULL) {
delete _value;
set_value(NULL);
}
}
template <> void DCmdArgument<MemorySizeArgument>::parse_value(const char* str,
size_t len, TRAPS) {
if (str == NULL) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Parsing error memory size value: syntax error, value is null\n");
}
if (*str == '-') {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Parsing error memory size value: negative values not allowed");
}
int res = sscanf(str, UINT64_FORMAT "%c", &_value._val, &_value._multiplier);
if (res == 2) {
switch (_value._multiplier) {
case 'k': case 'K':
_value._size = _value._val * 1024;
break;
case 'm': case 'M':
_value._size = _value._val * 1024 * 1024;
break;
case 'g': case 'G':
_value._size = _value._val * 1024 * 1024 * 1024;
break;
default:
_value._size = _value._val;
_value._multiplier = ' ';
break;
}
} else if (res == 1) {
_value._size = _value._val;
} else {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Parsing error memory size value: invalid value");
}
}
template <> void DCmdArgument<MemorySizeArgument>::init_value(TRAPS) {
if (has_default()) {
this->parse_value(_default_string, strlen(_default_string), THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Default string must be parsable");
}
} else {
_value._size = 0;
_value._val = 0;
_value._multiplier = ' ';
}
}
template <> void DCmdArgument<MemorySizeArgument>::destroy_value() { }
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticArgument.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.hpp"
#include "utilities/exceptions.hpp"
class StringArrayArgument : public CHeapObj<mtInternal> {
private:
GrowableArray<char*>* _array;
public:
StringArrayArgument() {
_array = new(ResourceObj::C_HEAP, mtInternal)GrowableArray<char *>(32, true);
assert(_array != NULL, "Sanity check");
}
void add(const char* str, size_t len) {
if (str != NULL) {
char* ptr = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
strncpy(ptr, str, len);
ptr[len] = 0;
_array->append(ptr);
}
}
GrowableArray<char*>* array() {
return _array;
}
~StringArrayArgument() {
for (int i=0; i<_array->length(); i++) {
if(_array->at(i) != NULL) { // Safety check
FREE_C_HEAP_ARRAY(char, _array->at(i), mtInternal);
}
}
delete _array;
}
};
class NanoTimeArgument {
public:
jlong _nanotime;
jlong _time;
char _unit[3];
};
class MemorySizeArgument {
public:
u8 _size;
u8 _val;
char _multiplier;
};
class GenDCmdArgument : public ResourceObj {
protected:
GenDCmdArgument* _next;
const char* _name;
const char* _description;
const char* _type;
const char* _default_string;
bool _is_set;
bool _is_mandatory;
bool _allow_multiple;
GenDCmdArgument(const char* name, const char* description, const char* type,
const char* default_string, bool mandatory) {
_name = name;
_description = description;
_type = type;
_default_string = default_string;
_is_mandatory = mandatory;
_is_set = false;
_allow_multiple = false;
};
public:
const char* name() { return _name; }
const char* description() { return _description; }
const char* type() { return _type; }
const char* default_string() { return _default_string; }
bool is_set() { return _is_set; }
void set_is_set(bool b) { _is_set = b; }
bool allow_multiple() { return _allow_multiple; }
bool is_mandatory() { return _is_mandatory; }
bool has_value() { return _is_set || _default_string != NULL; }
bool has_default() { return _default_string != NULL; }
void read_value(const char* str, size_t len, TRAPS);
virtual void parse_value(const char* str, size_t len, TRAPS) = 0;
virtual void init_value(TRAPS) = 0;
virtual void reset(TRAPS) = 0;
virtual void cleanup() = 0;
virtual void value_as_str(char* buf, size_t len) = 0;
void set_next(GenDCmdArgument* arg) {
_next = arg;
}
GenDCmdArgument* next() {
return _next;
}
void to_string(jlong l, char* buf, size_t len);
void to_string(bool b, char* buf, size_t len);
void to_string(char* c, char* buf, size_t len);
void to_string(NanoTimeArgument n, char* buf, size_t len);
void to_string(MemorySizeArgument f, char* buf, size_t len);
void to_string(StringArrayArgument* s, char* buf, size_t len);
};
template <class ArgType> class DCmdArgument: public GenDCmdArgument {
private:
ArgType _value;
public:
DCmdArgument(const char* name, const char* description, const char* type,
bool mandatory) :
GenDCmdArgument(name, description, type, NULL, mandatory) { }
DCmdArgument(const char* name, const char* description, const char* type,
bool mandatory, const char* defaultvalue) :
GenDCmdArgument(name, description, type, defaultvalue, mandatory)
{ }
~DCmdArgument() { destroy_value(); }
ArgType value() { return _value;}
void set_value(ArgType v) { _value = v; }
void reset(TRAPS) {
destroy_value();
init_value(CHECK);
_is_set = false;
}
void cleanup() {
destroy_value();
}
void parse_value(const char* str, size_t len, TRAPS);
void init_value(TRAPS);
void destroy_value();
void value_as_str(char *buf, size_t len) { return to_string(_value, buf, len);}
};
#endif /* SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP */
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticCommand.cpp
#include "precompiled.hpp"
#include "classfile/classLoaderStats.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "services/diagnosticArgument.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/heapDumper.hpp"
#include "services/management.hpp"
#include "utilities/macros.hpp"
#include "oops/objArrayOop.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
void DCmdRegistrant::register_dcmds(){
uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
| DCmd_Source_MBean;
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<FinalizerInfoDCmd>(full_export, true, false));
#if INCLUDE_SERVICES // Heap dumping/inspection supported
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
}
#ifndef HAVE_EXTRA_DCMD
void DCmdRegistrant::register_dcmds_ext(){
}
#endif
HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
_all("-all", "Show help for all commands", "BOOLEAN", false, "false"),
_cmd("command name", "The name of the command for which we want help",
"STRING", false) {
_dcmdparser.add_dcmd_option(&_all);
_dcmdparser.add_dcmd_argument(&_cmd);
};
void HelpDCmd::execute(DCmdSource source, TRAPS) {
if (_all.value()) {
GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
for (int i = 0; i < cmd_list->length(); i++) {
DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
strlen(cmd_list->at(i)));
output()->print_cr("%s%s", factory->name(),
factory->is_enabled() ? "" : " [disabled]");
output()->print_cr("\t%s", factory->description());
output()->cr();
factory = factory->next();
}
} else if (_cmd.has_value()) {
DCmd* cmd = NULL;
DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(),
strlen(_cmd.value()));
if (factory != NULL) {
output()->print_cr("%s%s", factory->name(),
factory->is_enabled() ? "" : " [disabled]");
output()->print_cr("%s", factory->description());
output()->print_cr("\nImpact: %s", factory->impact());
JavaPermission p = factory->permission();
if(p._class != NULL) {
if(p._action != NULL) {
output()->print_cr("\nPermission: %s(%s, %s)",
p._class, p._name == NULL ? "null" : p._name, p._action);
} else {
output()->print_cr("\nPermission: %s(%s)",
p._class, p._name == NULL ? "null" : p._name);
}
}
output()->cr();
cmd = factory->create_resource_instance(output());
if (cmd != NULL) {
DCmdMark mark(cmd);
cmd->print_help(factory->name());
}
} else {
output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value());
}
} else {
output()->print_cr("The following commands are available:");
GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
for (int i = 0; i < cmd_list->length(); i++) {
DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
strlen(cmd_list->at(i)));
output()->print_cr("%s%s", factory->name(),
factory->is_enabled() ? "" : " [disabled]");
factory = factory->_next;
}
output()->print_cr("\nFor more information about a specific command use 'help <command>'.");
}
}
int HelpDCmd::num_arguments() {
ResourceMark rm;
HelpDCmd* dcmd = new HelpDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void VersionDCmd::execute(DCmdSource source, TRAPS) {
output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(),
Abstract_VM_Version::vm_release());
JDK_Version jdk_version = JDK_Version::current();
if (jdk_version.update_version() > 0) {
output()->print_cr("JDK %d.%d_%02d", jdk_version.major_version(),
jdk_version.minor_version(), jdk_version.update_version());
} else {
output()->print_cr("JDK %d.%d", jdk_version.major_version(),
jdk_version.minor_version());
}
}
PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_all("-all", "Print all flags supported by the VM", "BOOLEAN", false, "false") {
_dcmdparser.add_dcmd_option(&_all);
}
void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) {
if (_all.value()) {
CommandLineFlags::printFlags(output(), true);
} else {
CommandLineFlags::printSetFlags(output());
}
}
int PrintVMFlagsDCmd::num_arguments() {
ResourceMark rm;
PrintVMFlagsDCmd* dcmd = new PrintVMFlagsDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
Symbol* klass = vmSymbols::sun_misc_VMSupport();
Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK);
instanceKlassHandle ik (THREAD, k);
if (ik->should_be_initialized()) {
ik->initialize(THREAD);
}
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, output());
output()->cr();
CLEAR_PENDING_EXCEPTION;
return;
}
JavaValue result(T_OBJECT);
JavaCallArguments args;
Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature();
JavaCalls::call_static(&result,
ik,
vmSymbols::serializePropertiesToByteArray_name(),
signature,
&args,
THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, output());
output()->cr();
CLEAR_PENDING_EXCEPTION;
return;
}
oop res = (oop)result.get_jobject();
assert(res->is_typeArray(), "just checking");
assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
typeArrayOop ba = typeArrayOop(res);
jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
output()->print_raw((const char*)addr, ba->length());
}
VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_date("-date", "Add a prefix with current date", "BOOLEAN", false, "false") {
_dcmdparser.add_dcmd_option(&_date);
}
void VMUptimeDCmd::execute(DCmdSource source, TRAPS) {
if (_date.value()) {
output()->date_stamp(true, "", ": ");
}
output()->time_stamp().update_to(tty->time_stamp().ticks());
output()->stamp();
output()->print_cr(" s");
}
int VMUptimeDCmd::num_arguments() {
ResourceMark rm;
VMUptimeDCmd* dcmd = new VMUptimeDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
if (!DisableExplicitGC) {
Universe::heap()->collect(GCCause::_java_lang_system_gc);
} else {
output()->print_cr("Explicit GC is disabled, no GC has been performed.");
}
}
void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(),
true, CHECK);
instanceKlassHandle klass(THREAD, k);
JavaValue result(T_VOID);
JavaCalls::call_static(&result, klass,
vmSymbols::run_finalization_name(),
vmSymbols::void_method_signature(), CHECK);
}
void HeapInfoDCmd::execute(DCmdSource source, TRAPS) {
Universe::heap()->print_on(output());
}
void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) {
ResourceMark rm;
Klass* k = SystemDictionary::resolve_or_null(
vmSymbols::finalizer_histogram_klass(), THREAD);
assert(k != NULL, "FinalizerHistogram class is not accessible");
instanceKlassHandle klass(THREAD, k);
JavaValue result(T_ARRAY);
JavaCalls::call_static(&result, klass,
vmSymbols::get_finalizer_histogram_name(),
vmSymbols::void_finalizer_histogram_entry_array_signature(), CHECK);
objArrayOop result_oop = (objArrayOop) result.get_jobject();
if (result_oop->length() == 0) {
output()->print_cr("No instances waiting for finalization found");
return;
}
oop foop = result_oop->obj_at(0);
InstanceKlass* ik = InstanceKlass::cast(foop->klass());
fieldDescriptor count_fd, name_fd;
Klass* count_res = ik->find_field(
vmSymbols::finalizer_histogram_entry_count_field(), vmSymbols::int_signature(), &count_fd);
Klass* name_res = ik->find_field(
vmSymbols::finalizer_histogram_entry_name_field(), vmSymbols::string_signature(), &name_fd);
assert(count_res != NULL && name_res != NULL, "Unexpected layout of FinalizerHistogramEntry");
output()->print_cr("Unreachable instances waiting for finalization");
output()->print_cr("#instances class name");
output()->print_cr("-----------------------");
for (int i = 0; i < result_oop->length(); ++i) {
oop element_oop = result_oop->obj_at(i);
oop str_oop = element_oop->obj_field(name_fd.offset());
char *name = java_lang_String::as_utf8_string(str_oop);
int count = element_oop->int_field(count_fd.offset());
output()->print_cr("%10d %s", count, name);
}
}
#if INCLUDE_SERVICES // Heap dumping/inspection supported
HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_filename("filename","Name of the dump file", "STRING",true),
_all("-all", "Dump all objects, including unreachable objects",
"BOOLEAN", false, "false") {
_dcmdparser.add_dcmd_option(&_all);
_dcmdparser.add_dcmd_argument(&_filename);
}
void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
HeapDumper dumper(!_all.value() /* request GC if _all is false*/);
int res = dumper.dump(_filename.value());
if (res == 0) {
output()->print_cr("Heap dump file created");
} else {
ResourceMark rm;
char* error = dumper.error_as_C_string();
if (error == NULL) {
output()->print_cr("Dump failed - reason unknown");
} else {
output()->print_cr("%s", error);
}
}
}
int HeapDumpDCmd::num_arguments() {
ResourceMark rm;
HeapDumpDCmd* dcmd = new HeapDumpDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_all("-all", "Inspect all objects, including unreachable objects",
"BOOLEAN", false, "false") {
_dcmdparser.add_dcmd_option(&_all);
}
void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
VM_GC_HeapInspection heapop(output(),
!_all.value() /* request full gc if false */);
VMThread::execute(&heapop);
}
int ClassHistogramDCmd::num_arguments() {
ResourceMark rm;
ClassHistogramDCmd* dcmd = new ClassHistogramDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
#define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total"
ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_csv("-csv", "Print in CSV (comma-separated values) format for spreadsheets",
"BOOLEAN", false, "false"),
_all("-all", "Show all columns",
"BOOLEAN", false, "false"),
_help("-help", "Show meaning of all the columns",
"BOOLEAN", false, "false"),
_columns("columns", "Comma-separated list of all the columns to show. "
"If not specified, the following columns are shown: " DEFAULT_COLUMNS,
"STRING", false) {
_dcmdparser.add_dcmd_option(&_all);
_dcmdparser.add_dcmd_option(&_csv);
_dcmdparser.add_dcmd_option(&_help);
_dcmdparser.add_dcmd_argument(&_columns);
}
void ClassStatsDCmd::execute(DCmdSource source, TRAPS) {
if (!UnlockDiagnosticVMOptions) {
output()->print_cr("GC.class_stats command requires -XX:+UnlockDiagnosticVMOptions");
return;
}
VM_GC_HeapInspection heapop(output(),
true /* request_full_gc */);
heapop.set_csv_format(_csv.value());
heapop.set_print_help(_help.value());
heapop.set_print_class_stats(true);
if (_all.value()) {
if (_columns.has_value()) {
output()->print_cr("Cannot specify -all and individual columns at the same time");
return;
} else {
heapop.set_columns(NULL);
}
} else {
if (_columns.has_value()) {
heapop.set_columns(_columns.value());
} else {
heapop.set_columns(DEFAULT_COLUMNS);
}
}
VMThread::execute(&heapop);
}
int ClassStatsDCmd::num_arguments() {
ResourceMark rm;
ClassStatsDCmd* dcmd = new ClassStatsDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
#endif // INCLUDE_SERVICES
ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") {
_dcmdparser.add_dcmd_option(&_locks);
}
void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) {
VM_PrintThreads op1(output(), _locks.value());
VMThread::execute(&op1);
VM_PrintJNI op2(output());
VMThread::execute(&op2);
VM_FindDeadlocks op3(output());
VMThread::execute(&op3);
}
int ThreadDumpDCmd::num_arguments() {
ResourceMark rm;
ThreadDumpDCmd* dcmd = new ThreadDumpDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated) :
DCmdWithParser(output, heap_allocated),
_config_file
("config.file",
"set com.sun.management.config.file", "STRING", false),
_jmxremote_host
("jmxremote.host",
"set com.sun.management.jmxremote.host", "STRING", false),
_jmxremote_port
("jmxremote.port",
"set com.sun.management.jmxremote.port", "STRING", false),
_jmxremote_rmi_port
("jmxremote.rmi.port",
"set com.sun.management.jmxremote.rmi.port", "STRING", false),
_jmxremote_ssl
("jmxremote.ssl",
"set com.sun.management.jmxremote.ssl", "STRING", false),
_jmxremote_registry_ssl
("jmxremote.registry.ssl",
"set com.sun.management.jmxremote.registry.ssl", "STRING", false),
_jmxremote_authenticate
("jmxremote.authenticate",
"set com.sun.management.jmxremote.authenticate", "STRING", false),
_jmxremote_password_file
("jmxremote.password.file",
"set com.sun.management.jmxremote.password.file", "STRING", false),
_jmxremote_access_file
("jmxremote.access.file",
"set com.sun.management.jmxremote.access.file", "STRING", false),
_jmxremote_login_config
("jmxremote.login.config",
"set com.sun.management.jmxremote.login.config", "STRING", false),
_jmxremote_ssl_enabled_cipher_suites
("jmxremote.ssl.enabled.cipher.suites",
"set com.sun.management.jmxremote.ssl.enabled.cipher.suite", "STRING", false),
_jmxremote_ssl_enabled_protocols
("jmxremote.ssl.enabled.protocols",
"set com.sun.management.jmxremote.ssl.enabled.protocols", "STRING", false),
_jmxremote_ssl_need_client_auth
("jmxremote.ssl.need.client.auth",
"set com.sun.management.jmxremote.need.client.auth", "STRING", false),
_jmxremote_ssl_config_file
("jmxremote.ssl.config.file",
"set com.sun.management.jmxremote.ssl_config_file", "STRING", false),
_jmxremote_autodiscovery
("jmxremote.autodiscovery",
"set com.sun.management.jmxremote.autodiscovery", "STRING", false),
_jdp_port
("jdp.port",
"set com.sun.management.jdp.port", "INT", false),
_jdp_address
("jdp.address",
"set com.sun.management.jdp.address", "STRING", false),
_jdp_source_addr
("jdp.source_addr",
"set com.sun.management.jdp.source_addr", "STRING", false),
_jdp_ttl
("jdp.ttl",
"set com.sun.management.jdp.ttl", "INT", false),
_jdp_pause
("jdp.pause",
"set com.sun.management.jdp.pause", "INT", false),
_jdp_name
("jdp.name",
"set com.sun.management.jdp.name", "STRING", false)
{
_dcmdparser.add_dcmd_option(&_config_file);
_dcmdparser.add_dcmd_option(&_jmxremote_host);
_dcmdparser.add_dcmd_option(&_jmxremote_port);
_dcmdparser.add_dcmd_option(&_jmxremote_rmi_port);
_dcmdparser.add_dcmd_option(&_jmxremote_ssl);
_dcmdparser.add_dcmd_option(&_jmxremote_registry_ssl);
_dcmdparser.add_dcmd_option(&_jmxremote_authenticate);
_dcmdparser.add_dcmd_option(&_jmxremote_password_file);
_dcmdparser.add_dcmd_option(&_jmxremote_access_file);
_dcmdparser.add_dcmd_option(&_jmxremote_login_config);
_dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_cipher_suites);
_dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_protocols);
_dcmdparser.add_dcmd_option(&_jmxremote_ssl_need_client_auth);
_dcmdparser.add_dcmd_option(&_jmxremote_ssl_config_file);
_dcmdparser.add_dcmd_option(&_jmxremote_autodiscovery);
_dcmdparser.add_dcmd_option(&_jdp_port);
_dcmdparser.add_dcmd_option(&_jdp_address);
_dcmdparser.add_dcmd_option(&_jdp_source_addr);
_dcmdparser.add_dcmd_option(&_jdp_ttl);
_dcmdparser.add_dcmd_option(&_jdp_pause);
_dcmdparser.add_dcmd_option(&_jdp_name);
}
int JMXStartRemoteDCmd::num_arguments() {
ResourceMark rm;
JMXStartRemoteDCmd* dcmd = new JMXStartRemoteDCmd(NULL, false);
if (dcmd != NULL) {
DCmdMark mark(dcmd);
return dcmd->_dcmdparser.num_arguments();
} else {
return 0;
}
}
void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK);
instanceKlassHandle ik (THREAD, k);
JavaValue result(T_VOID);
int len = 0;
stringStream options;
char comma[2] = {0,0};
#define PUT_OPTION(a) \
if ( (a).is_set() ){ \
options.print(\
( *((a).type()) == 'I' ) ? "%scom.sun.management.%s=%d" : "%scom.sun.management.%s=%s",\
comma, (a).name(), (a).value()); \
comma[0] = ','; \
}
PUT_OPTION(_config_file);
PUT_OPTION(_jmxremote_host);
PUT_OPTION(_jmxremote_port);
PUT_OPTION(_jmxremote_rmi_port);
PUT_OPTION(_jmxremote_ssl);
PUT_OPTION(_jmxremote_registry_ssl);
PUT_OPTION(_jmxremote_authenticate);
PUT_OPTION(_jmxremote_password_file);
PUT_OPTION(_jmxremote_access_file);
PUT_OPTION(_jmxremote_login_config);
PUT_OPTION(_jmxremote_ssl_enabled_cipher_suites);
PUT_OPTION(_jmxremote_ssl_enabled_protocols);
PUT_OPTION(_jmxremote_ssl_need_client_auth);
PUT_OPTION(_jmxremote_ssl_config_file);
PUT_OPTION(_jmxremote_autodiscovery);
PUT_OPTION(_jdp_port);
PUT_OPTION(_jdp_address);
PUT_OPTION(_jdp_source_addr);
PUT_OPTION(_jdp_ttl);
PUT_OPTION(_jdp_pause);
PUT_OPTION(_jdp_name);
#undef PUT_OPTION
Handle str = java_lang_String::create_from_str(options.as_string(), CHECK);
JavaCalls::call_static(&result, ik, vmSymbols::startRemoteAgent_name(), vmSymbols::string_void_signature(), str, CHECK);
}
JMXStartLocalDCmd::JMXStartLocalDCmd(outputStream *output, bool heap_allocated) :
DCmd(output, heap_allocated) {
}
void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK);
instanceKlassHandle ik (THREAD, k);
JavaValue result(T_VOID);
JavaCalls::call_static(&result, ik, vmSymbols::startLocalAgent_name(), vmSymbols::void_method_signature(), CHECK);
}
void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::sun_management_Agent(), loader, Handle(), true, CHECK);
instanceKlassHandle ik (THREAD, k);
JavaValue result(T_VOID);
JavaCalls::call_static(&result, ik, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
}
VMDynamicLibrariesDCmd::VMDynamicLibrariesDCmd(outputStream *output, bool heap_allocated) :
DCmd(output, heap_allocated) {
}
void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) {
os::print_dll_info(output());
output()->cr();
}
void RotateGCLogDCmd::execute(DCmdSource source, TRAPS) {
if (UseGCLogFileRotation) {
VM_RotateGCLog rotateop(output());
VMThread::execute(&rotateop);
} else {
output()->print_cr("Target VM does not support GC log file rotation.");
}
}
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticCommand.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
#include "runtime/arguments.hpp"
#include "classfile/vmSymbols.hpp"
#include "utilities/ostream.hpp"
#include "runtime/vm_version.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/os.hpp"
#include "services/diagnosticArgument.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/diagnosticCommand_ext.hpp"
#include "utilities/macros.hpp"
class HelpDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _all;
DCmdArgument<char*> _cmd;
public:
HelpDCmd(outputStream* output, bool heap);
static const char* name() { return "help"; }
static const char* description() {
return "For more information about a specific command use 'help <command>'. "
"With no argument this will show a list of available commands. "
"'help all' will show help for all commands.";
}
static const char* impact() { return "Low"; }
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class VersionDCmd : public DCmd {
public:
VersionDCmd(outputStream* output, bool heap) : DCmd(output,heap) { }
static const char* name() { return "VM.version"; }
static const char* description() {
return "Print JVM version information.";
}
static const char* impact() { return "Low"; }
static const JavaPermission permission() {
JavaPermission p = {"java.util.PropertyPermission",
"java.vm.version", "read"};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
class CommandLineDCmd : public DCmd {
public:
CommandLineDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
static const char* name() { return "VM.command_line"; }
static const char* description() {
return "Print the command line used to start this VM instance.";
}
static const char* impact() { return "Low"; }
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS) {
Arguments::print_on(_output);
}
};
class PrintSystemPropertiesDCmd : public DCmd {
public:
PrintSystemPropertiesDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
static const char* name() { return "VM.system_properties"; }
static const char* description() {
return "Print system properties.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.util.PropertyPermission",
"*", "read"};
return p;
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
class PrintVMFlagsDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _all;
public:
PrintVMFlagsDCmd(outputStream* output, bool heap);
static const char* name() { return "VM.flags"; }
static const char* description() {
return "Print VM flag options and their current values.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class VMDynamicLibrariesDCmd : public DCmd {
public:
VMDynamicLibrariesDCmd(outputStream* output, bool heap);
static const char* name() {
return "VM.dynlibs";
}
static const char* description() {
return "Print loaded dynamic libraries.";
}
static const char* impact() {
return "Low";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments() {
return 0;
};
virtual void execute(DCmdSource source, TRAPS);
};
class VMUptimeDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _date;
public:
VMUptimeDCmd(outputStream* output, bool heap);
static const char* name() { return "VM.uptime"; }
static const char* description() {
return "Print VM uptime.";
}
static const char* impact() {
return "Low";
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class SystemGCDCmd : public DCmd {
public:
SystemGCDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
static const char* name() { return "GC.run"; }
static const char* description() {
return "Call java.lang.System.gc().";
}
static const char* impact() {
return "Medium: Depends on Java heap size and content.";
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
class RunFinalizationDCmd : public DCmd {
public:
RunFinalizationDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
static const char* name() { return "GC.run_finalization"; }
static const char* description() {
return "Call java.lang.System.runFinalization().";
}
static const char* impact() {
return "Medium: Depends on Java content.";
}
static int num_arguments() { return 0; }
virtual void execute(DCmdSource source, TRAPS);
};
class HeapInfoDCmd : public DCmd {
public:
HeapInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
static const char* name() { return "GC.heap_info"; }
static const char* description() {
return "Provide generic Java heap information.";
}
static const char* impact() {
return "Medium";
}
static int num_arguments() { return 0; }
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
virtual void execute(DCmdSource source, TRAPS);
};
class FinalizerInfoDCmd : public DCmd {
public:
FinalizerInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
static const char* name() { return "GC.finalizer_info"; }
static const char* description() {
return "Provide information about Java finalization queue.";
}
static const char* impact() {
return "Medium";
}
static int num_arguments() { return 0; }
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
virtual void execute(DCmdSource source, TRAPS);
};
#if INCLUDE_SERVICES // Heap dumping supported
class HeapDumpDCmd : public DCmdWithParser {
protected:
DCmdArgument<char*> _filename;
DCmdArgument<bool> _all;
public:
HeapDumpDCmd(outputStream* output, bool heap);
static const char* name() {
return "GC.heap_dump";
}
static const char* description() {
return "Generate a HPROF format dump of the Java heap.";
}
static const char* impact() {
return "High: Depends on Java heap size and content. "
"Request a full GC unless the '-all' option is specified.";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
#endif // INCLUDE_SERVICES
class ClassHistogramDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _all;
public:
ClassHistogramDCmd(outputStream* output, bool heap);
static const char* name() {
return "GC.class_histogram";
}
static const char* description() {
return "Provide statistics about the Java heap usage.";
}
static const char* impact() {
return "High: Depends on Java heap size and content.";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class ClassStatsDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _all;
DCmdArgument<bool> _csv;
DCmdArgument<bool> _help;
DCmdArgument<char*> _columns;
public:
ClassStatsDCmd(outputStream* output, bool heap);
static const char* name() {
return "GC.class_stats";
}
static const char* description() {
return "Provide statistics about Java class meta data. Requires -XX:+UnlockDiagnosticVMOptions.";
}
static const char* impact() {
return "High: Depends on Java heap size and content.";
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class ThreadDumpDCmd : public DCmdWithParser {
protected:
DCmdArgument<bool> _locks;
public:
ThreadDumpDCmd(outputStream* output, bool heap);
static const char* name() { return "Thread.print"; }
static const char* description() {
return "Print all threads with stacktraces.";
}
static const char* impact() {
return "Medium: Depends on the number of threads.";
}
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"monitor", NULL};
return p;
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class JMXStartRemoteDCmd : public DCmdWithParser {
DCmdArgument<char *> _config_file;
DCmdArgument<char *> _jmxremote_host;
DCmdArgument<char *> _jmxremote_port;
DCmdArgument<char *> _jmxremote_rmi_port;
DCmdArgument<char *> _jmxremote_ssl;
DCmdArgument<char *> _jmxremote_registry_ssl;
DCmdArgument<char *> _jmxremote_authenticate;
DCmdArgument<char *> _jmxremote_password_file;
DCmdArgument<char *> _jmxremote_access_file;
DCmdArgument<char *> _jmxremote_login_config;
DCmdArgument<char *> _jmxremote_ssl_enabled_cipher_suites;
DCmdArgument<char *> _jmxremote_ssl_enabled_protocols;
DCmdArgument<char *> _jmxremote_ssl_need_client_auth;
DCmdArgument<char *> _jmxremote_ssl_config_file;
DCmdArgument<char *> _jmxremote_autodiscovery;
DCmdArgument<jlong> _jdp_port;
DCmdArgument<char *> _jdp_address;
DCmdArgument<char *> _jdp_source_addr;
DCmdArgument<jlong> _jdp_ttl;
DCmdArgument<jlong> _jdp_pause;
DCmdArgument<char *> _jdp_name;
public:
JMXStartRemoteDCmd(outputStream *output, bool heap_allocated);
static const char *name() {
return "ManagementAgent.start";
}
static const char *description() {
return "Start remote management agent.";
}
static int num_arguments();
virtual void execute(DCmdSource source, TRAPS);
};
class JMXStartLocalDCmd : public DCmd {
public:
JMXStartLocalDCmd(outputStream *output, bool heap_allocated);
static const char *name() {
return "ManagementAgent.start_local";
}
static const char *description() {
return "Start local management agent.";
}
virtual void execute(DCmdSource source, TRAPS);
};
class JMXStopRemoteDCmd : public DCmd {
public:
JMXStopRemoteDCmd(outputStream *output, bool heap_allocated) :
DCmd(output, heap_allocated) {
}
static const char *name() {
return "ManagementAgent.stop";
}
static const char *description() {
return "Stop remote management agent.";
}
virtual void execute(DCmdSource source, TRAPS);
};
class RotateGCLogDCmd : public DCmd {
public:
RotateGCLogDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
static const char* name() { return "GC.rotate_log"; }
static const char* description() {
return "Force the GC log file to be rotated.";
}
static const char* impact() { return "Low"; }
virtual void execute(DCmdSource source, TRAPS);
static int num_arguments() { return 0; }
static const JavaPermission permission() {
JavaPermission p = {"java.lang.management.ManagementPermission",
"control", NULL};
return p;
}
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticCommand_ext.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_EXT_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_EXT_HPP
#undef HAVE_EXTRA_DCMD
#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticFramework.cpp
#include "precompiled.hpp"
#include "memory/oopFactory.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/diagnosticArgument.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/management.hpp"
CmdLine::CmdLine(const char* line, size_t len, bool no_command_name) {
assert(line != NULL, "Command line string should not be NULL");
const char* line_end;
const char* cmd_end;
_cmd = line;
line_end = &line[len];
while (_cmd < line_end && isspace((int) _cmd[0])) {
_cmd++;
}
cmd_end = _cmd;
if (no_command_name) {
_cmd = NULL;
_cmd_len = 0;
} else {
while (cmd_end < line_end && !isspace((int) cmd_end[0])) {
cmd_end++;
}
_cmd_len = cmd_end - _cmd;
}
_args = cmd_end;
_args_len = line_end - _args;
}
bool DCmdArgIter::next(TRAPS) {
if (_len == 0) return false;
while (_cursor < _len - 1 && _buffer[_cursor] == _delim) {
_cursor++;
}
if (_cursor >= _len - 1) {
_cursor = _len - 1;
_key_addr = &_buffer[_len - 1];
_key_len = 0;
_value_addr = &_buffer[_len - 1];
_value_len = 0;
return false;
}
_key_addr = &_buffer[_cursor];
bool arg_had_quotes = false;
while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) {
if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {
_key_addr++;
char quote = _buffer[_cursor];
arg_had_quotes = true;
while (_cursor < _len - 1) {
_cursor++;
if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {
break;
}
}
if (_buffer[_cursor] != quote) {
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
"Format error in diagnostic command arguments", false);
}
break;
}
_cursor++;
}
_key_len = &_buffer[_cursor] - _key_addr;
if (arg_had_quotes) {
_cursor++;
}
if (_cursor <= _len -1 && _buffer[_cursor] == '=') {
_cursor++;
_value_addr = &_buffer[_cursor];
bool value_had_quotes = false;
while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) {
if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {
_value_addr++;
char quote = _buffer[_cursor];
value_had_quotes = true;
while (_cursor < _len - 1) {
_cursor++;
if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {
break;
}
}
if (_buffer[_cursor] != quote) {
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
"Format error in diagnostic command arguments", false);
}
break;
}
_cursor++;
}
_value_len = &_buffer[_cursor] - _value_addr;
if (value_had_quotes) {
_cursor++;
}
} else {
_value_addr = NULL;
_value_len = 0;
}
return _key_len != 0;
}
bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) {
if (info == NULL) return false;
return strcmp((const char*)cmd_name, info->name()) == 0;
}
void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) {
assert(arg != NULL, "Sanity");
if (_options == NULL) {
_options = arg;
} else {
GenDCmdArgument* o = _options;
while (o->next() != NULL) {
o = o->next();
}
o->set_next(arg);
}
arg->set_next(NULL);
Thread* THREAD = Thread::current();
arg->init_value(THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Initialization must be successful");
}
}
void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) {
assert(arg != NULL, "Sanity");
if (_arguments_list == NULL) {
_arguments_list = arg;
} else {
GenDCmdArgument* a = _arguments_list;
while (a->next() != NULL) {
a = a->next();
}
a->set_next(arg);
}
arg->set_next(NULL);
Thread* THREAD = Thread::current();
arg->init_value(THREAD);
if (HAS_PENDING_EXCEPTION) {
fatal("Initialization must be successful");
}
}
void DCmdParser::parse(CmdLine* line, char delim, TRAPS) {
GenDCmdArgument* next_argument = _arguments_list;
DCmdArgIter iter(line->args_addr(), line->args_len(), delim);
bool cont = iter.next(CHECK);
while (cont) {
GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(),
iter.key_length());
if (arg != NULL) {
arg->read_value(iter.value_addr(), iter.value_length(), CHECK);
} else {
if (next_argument != NULL) {
arg = next_argument;
arg->read_value(iter.key_addr(), iter.key_length(), CHECK);
next_argument = next_argument->next();
} else {
const size_t buflen = 120;
const size_t argbuflen = 30;
char buf[buflen];
char argbuf[argbuflen];
size_t len = MIN2<size_t>(iter.key_length(), argbuflen - 1);
strncpy(argbuf, iter.key_addr(), len);
argbuf[len] = '\0';
jio_snprintf(buf, buflen - 1, "Unknown argument '%s' in diagnostic command.", argbuf);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
}
}
cont = iter.next(CHECK);
}
check(CHECK);
}
GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) {
GenDCmdArgument* arg = _options;
while (arg != NULL) {
if (strlen(arg->name()) == len &&
strncmp(name, arg->name(), len) == 0) {
return arg;
}
arg = arg->next();
}
return NULL;
}
void DCmdParser::check(TRAPS) {
const size_t buflen = 256;
char buf[buflen];
GenDCmdArgument* arg = _arguments_list;
while (arg != NULL) {
if (arg->is_mandatory() && !arg->has_value()) {
jio_snprintf(buf, buflen - 1, "The argument '%s' is mandatory.", arg->name());
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
}
arg = arg->next();
}
arg = _options;
while (arg != NULL) {
if (arg->is_mandatory() && !arg->has_value()) {
jio_snprintf(buf, buflen - 1, "The option '%s' is mandatory.", arg->name());
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);
}
arg = arg->next();
}
}
void DCmdParser::print_help(outputStream* out, const char* cmd_name) {
out->print("Syntax : %s %s", cmd_name, _options == NULL ? "" : "[options]");
GenDCmdArgument* arg = _arguments_list;
while (arg != NULL) {
if (arg->is_mandatory()) {
out->print(" <%s>", arg->name());
} else {
out->print(" [<%s>]", arg->name());
}
arg = arg->next();
}
out->cr();
if (_arguments_list != NULL) {
out->print_cr("\nArguments:");
arg = _arguments_list;
while (arg != NULL) {
out->print("\t%s : %s %s (%s, ", arg->name(),
arg->is_mandatory() ? "" : "[optional]",
arg->description(), arg->type());
if (arg->has_default()) {
out->print("%s", arg->default_string());
} else {
out->print("no default value");
}
out->print_cr(")");
arg = arg->next();
}
}
if (_options != NULL) {
out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)");
arg = _options;
while (arg != NULL) {
out->print("\t%s : %s %s (%s, ", arg->name(),
arg->is_mandatory() ? "" : "[optional]",
arg->description(), arg->type());
if (arg->has_default()) {
out->print("%s", arg->default_string());
} else {
out->print("no default value");
}
out->print_cr(")");
arg = arg->next();
}
}
}
void DCmdParser::reset(TRAPS) {
GenDCmdArgument* arg = _arguments_list;
while (arg != NULL) {
arg->reset(CHECK);
arg = arg->next();
}
arg = _options;
while (arg != NULL) {
arg->reset(CHECK);
arg = arg->next();
}
}
void DCmdParser::cleanup() {
GenDCmdArgument* arg = _arguments_list;
while (arg != NULL) {
arg->cleanup();
arg = arg->next();
}
arg = _options;
while (arg != NULL) {
arg->cleanup();
arg = arg->next();
}
}
int DCmdParser::num_arguments() {
GenDCmdArgument* arg = _arguments_list;
int count = 0;
while (arg != NULL) {
count++;
arg = arg->next();
}
arg = _options;
while (arg != NULL) {
count++;
arg = arg->next();
}
return count;
}
GrowableArray<const char *>* DCmdParser::argument_name_array() {
int count = num_arguments();
GrowableArray<const char *>* array = new GrowableArray<const char *>(count);
GenDCmdArgument* arg = _arguments_list;
while (arg != NULL) {
array->append(arg->name());
arg = arg->next();
}
arg = _options;
while (arg != NULL) {
array->append(arg->name());
arg = arg->next();
}
return array;
}
GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() {
int count = num_arguments();
GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count);
int idx = 0;
GenDCmdArgument* arg = _arguments_list;
while (arg != NULL) {
array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
arg->type(), arg->default_string(), arg->is_mandatory(),
false, arg->allow_multiple(), idx));
idx++;
arg = arg->next();
}
arg = _options;
while (arg != NULL) {
array->append(new DCmdArgumentInfo(arg->name(), arg->description(),
arg->type(), arg->default_string(), arg->is_mandatory(),
true, arg->allow_multiple()));
arg = arg->next();
}
return array;
}
DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL;
bool DCmdFactory::_has_pending_jmx_notification = false;
void DCmd::parse_and_execute(DCmdSource source, outputStream* out,
const char* cmdline, char delim, TRAPS) {
if (cmdline == NULL) return; // Nothing to do!
DCmdIter iter(cmdline, '\n');
int count = 0;
while (iter.has_next()) {
if(source == DCmd_Source_MBean && count > 0) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"Invalid syntax");
}
CmdLine line = iter.next();
if (line.is_stop()) {
break;
}
if (line.is_executable()) {
DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK);
assert(command != NULL, "command error must be handled before this line");
DCmdMark mark(command);
command->parse(&line, delim, CHECK);
command->execute(source, CHECK);
}
count++;
}
}
void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) {
_dcmdparser.parse(line, delim, CHECK);
}
void DCmdWithParser::print_help(const char* name) {
_dcmdparser.print_help(output(), name);
}
void DCmdWithParser::reset(TRAPS) {
_dcmdparser.reset(CHECK);
}
void DCmdWithParser::cleanup() {
_dcmdparser.cleanup();
}
GrowableArray<const char*>* DCmdWithParser::argument_name_array() {
return _dcmdparser.argument_name_array();
}
GrowableArray<DCmdArgumentInfo*>* DCmdWithParser::argument_info_array() {
return _dcmdparser.argument_info_array();
}
void DCmdFactory::push_jmx_notification_request() {
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
_has_pending_jmx_notification = true;
Service_lock->notify_all();
}
void DCmdFactory::send_notification(TRAPS) {
DCmdFactory::send_notification_internal(THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
}
void DCmdFactory::send_notification_internal(TRAPS) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
bool notif = false;
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
notif = _has_pending_jmx_notification;
_has_pending_jmx_notification = false;
}
if (notif) {
Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK);
instanceKlassHandle mgmt_factory_helper_klass(THREAD, k);
JavaValue result(T_OBJECT);
JavaCalls::call_static(&result,
mgmt_factory_helper_klass,
vmSymbols::getDiagnosticCommandMBean_name(),
vmSymbols::getDiagnosticCommandMBean_signature(),
CHECK);
instanceOop m = (instanceOop) result.get_jobject();
instanceHandle dcmd_mbean_h(THREAD, m);
Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK);
instanceKlassHandle dcmd_mbean_klass(THREAD, k2);
if (!dcmd_mbean_h->is_a(k2)) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance");
}
JavaValue result2(T_VOID);
JavaCallArguments args2(dcmd_mbean_h);
JavaCalls::call_virtual(&result2,
dcmd_mbean_klass,
vmSymbols::createDiagnosticFrameworkNotification_name(),
vmSymbols::void_method_signature(),
&args2,
CHECK);
}
}
Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);
bool DCmdFactory::_send_jmx_notification = false;
DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) {
MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
DCmdFactory* factory = _DCmdFactoryList;
while (factory != NULL) {
if (strlen(factory->name()) == len &&
strncmp(name, factory->name(), len) == 0) {
if(factory->export_flags() & source) {
return factory;
} else {
return NULL;
}
}
factory = factory->_next;
}
return NULL;
}
int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) {
MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
factory->_next = _DCmdFactoryList;
_DCmdFactoryList = factory;
if (_send_jmx_notification && !factory->_hidden
&& (factory->_export_flags & DCmd_Source_MBean)) {
DCmdFactory::push_jmx_notification_request();
}
return 0; // Actually, there's no checks for duplicates
}
DCmd* DCmdFactory::create_global_DCmd(DCmdSource source, CmdLine &line,
outputStream* out, TRAPS) {
DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
if (f != NULL) {
if (f->is_enabled()) {
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
f->disabled_message());
}
return f->create_Cheap_instance(out);
}
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
"Unknown diagnostic command");
}
DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line,
outputStream* out, TRAPS) {
DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());
if (f != NULL) {
if (!f->is_enabled()) {
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
f->disabled_message());
}
return f->create_resource_instance(out);
}
THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
"Unknown diagnostic command");
}
GrowableArray<const char*>* DCmdFactory::DCmd_list(DCmdSource source) {
MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
GrowableArray<const char*>* array = new GrowableArray<const char*>();
DCmdFactory* factory = _DCmdFactoryList;
while (factory != NULL) {
if (!factory->is_hidden() && (factory->export_flags() & source)) {
array->append(factory->name());
}
factory = factory->next();
}
return array;
}
GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list(DCmdSource source ) {
MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);
GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>();
DCmdFactory* factory = _DCmdFactoryList;
while (factory != NULL) {
if (!factory->is_hidden() && (factory->export_flags() & source)) {
array->append(new DCmdInfo(factory->name(),
factory->description(), factory->impact(),
factory->permission(), factory->num_arguments(),
factory->is_enabled()));
}
factory = factory->next();
}
return array;
}
C:\hotspot-69087d08d473\src\share\vm/services/diagnosticFramework.hpp
#ifndef SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
#define SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.hpp"
#include "runtime/arguments.hpp"
#include "runtime/os.hpp"
#include "runtime/vm_version.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/ostream.hpp"
enum DCmdSource {
DCmd_Source_Internal = 0x01U, // invocation from the JVM
DCmd_Source_AttachAPI = 0x02U, // invocation via the attachAPI
DCmd_Source_MBean = 0x04U // invocation via a MBean
};
struct JavaPermission {
const char* _class;
const char* _name;
const char* _action;
};
class CmdLine : public StackObj {
private:
const char* _cmd;
size_t _cmd_len;
const char* _args;
size_t _args_len;
public:
CmdLine(const char* line, size_t len, bool no_command_name);
const char* args_addr() const { return _args; }
size_t args_len() const { return _args_len; }
const char* cmd_addr() const { return _cmd; }
size_t cmd_len() const { return _cmd_len; }
bool is_empty() { return _cmd_len == 0; }
bool is_executable() { return is_empty() || _cmd[0] != '#'; }
bool is_stop() { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; }
};
class DCmdIter : public StackObj {
friend class DCmd;
private:
const char* _str;
char _delim;
size_t _len;
size_t _cursor;
public:
DCmdIter(const char* str, char delim) {
_str = str;
_delim = delim;
_len = strlen(str);
_cursor = 0;
}
bool has_next() { return _cursor < _len; }
CmdLine next() {
assert(_cursor <= _len, "Cannot iterate more");
size_t n = _cursor;
while (n < _len && _str[n] != _delim) n++;
CmdLine line(&(_str[_cursor]), n - _cursor, false);
_cursor = n + 1;
return line;
}
};
class DCmdArgIter : public ResourceObj {
const char* _buffer;
size_t _len;
size_t _cursor;
const char* _key_addr;
size_t _key_len;
const char* _value_addr;
size_t _value_len;
char _delim;
public:
DCmdArgIter(const char* buf, size_t len, char delim) {
_buffer = buf;
_len = len;
_delim = delim;
_cursor = 0;
}
bool next(TRAPS);
const char* key_addr() { return _key_addr; }
size_t key_length() { return _key_len; }
const char* value_addr() { return _value_addr; }
size_t value_length() { return _value_len; }
};
class DCmdInfo : public ResourceObj {
protected:
const char* _name; /* Name of the diagnostic command */
const char* _description; /* Short description */
const char* _impact; /* Impact on the JVM */
JavaPermission _permission; /* Java Permission required to execute this command if any */
int _num_arguments; /* Number of supported options or arguments */
bool _is_enabled; /* True if the diagnostic command can be invoked, false otherwise */
public:
DCmdInfo(const char* name,
const char* description,
const char* impact,
JavaPermission permission,
int num_arguments,
bool enabled) {
this->_name = name;
this->_description = description;
this->_impact = impact;
this->_permission = permission;
this->_num_arguments = num_arguments;
this->_is_enabled = enabled;
}
const char* name() const { return _name; }
const char* description() const { return _description; }
const char* impact() const { return _impact; }
JavaPermission permission() const { return _permission; }
int num_arguments() const { return _num_arguments; }
bool is_enabled() const { return _is_enabled; }
static bool by_name(void* name, DCmdInfo* info);
};
class DCmdArgumentInfo : public ResourceObj {
protected:
const char* _name; /* Option/Argument name*/
const char* _description; /* Short description */
const char* _type; /* Type: STRING, BOOLEAN, etc. */
const char* _default_string; /* Default value in a parsable string */
bool _mandatory; /* True if the option/argument is mandatory */
bool _option; /* True if it is an option, false if it is an argument */
bool _multiple; /* True is the option can be specified several time */
int _position; /* Expected position for this argument (this field is */
public:
DCmdArgumentInfo(const char* name, const char* description, const char* type,
const char* default_string, bool mandatory, bool option,
bool multiple) {
this->_name = name;
this->_description = description;
this->_type = type;
this->_default_string = default_string;
this->_option = option;
this->_mandatory = mandatory;
this->_option = option;
this->_multiple = multiple;
this->_position = -1;
}
DCmdArgumentInfo(const char* name, const char* description, const char* type,
const char* default_string, bool mandatory, bool option,
bool multiple, int position) {
this->_name = name;
this->_description = description;
this->_type = type;
this->_default_string = default_string;
this->_option = option;
this->_mandatory = mandatory;
this->_option = option;
this->_multiple = multiple;
this->_position = position;
}
const char* name() const { return _name; }
const char* description() const { return _description; }
const char* type() const { return _type; }
const char* default_string() const { return _default_string; }
bool is_mandatory() const { return _mandatory; }
bool is_option() const { return _option; }
bool is_multiple() const { return _multiple; }
int position() const { return _position; }
};
class DCmdParser {
private:
GenDCmdArgument* _options;
GenDCmdArgument* _arguments_list;
char _delim;
public:
DCmdParser() {
_options = NULL;
_arguments_list = NULL;
_delim = ' ';
}
void add_dcmd_option(GenDCmdArgument* arg);
void add_dcmd_argument(GenDCmdArgument* arg);
GenDCmdArgument* lookup_dcmd_option(const char* name, size_t len);
GenDCmdArgument* arguments_list() { return _arguments_list; };
void check(TRAPS);
void parse(CmdLine* line, char delim, TRAPS);
void print_help(outputStream* out, const char* cmd_name);
void reset(TRAPS);
void cleanup();
int num_arguments();
GrowableArray<const char*>* argument_name_array();
GrowableArray<DCmdArgumentInfo*>* argument_info_array();
};
class DCmd : public ResourceObj {
protected:
outputStream* _output;
bool _is_heap_allocated;
public:
DCmd(outputStream* output, bool heap_allocated) {
_output = output;
_is_heap_allocated = heap_allocated;
}
static const char* name() { return "No Name";}
static const char* description() { return "No Help";}
static const char* disabled_message() { return "Diagnostic command currently disabled"; }
static const char* impact() { return "Low: No impact"; }
static const JavaPermission permission() {
JavaPermission p = {NULL, NULL, NULL};
return p;
}
static int num_arguments() { return 0; }
outputStream* output() { return _output; }
bool is_heap_allocated() { return _is_heap_allocated; }
virtual void print_help(const char* name) {
output()->print_cr("Syntax: %s", name);
}
virtual void parse(CmdLine* line, char delim, TRAPS) {
DCmdArgIter iter(line->args_addr(), line->args_len(), delim);
bool has_arg = iter.next(CHECK);
if (has_arg) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"The argument list of this diagnostic command should be empty.");
}
}
virtual void execute(DCmdSource source, TRAPS) { }
virtual void reset(TRAPS) { }
virtual void cleanup() { }
virtual GrowableArray<const char*>* argument_name_array() {
GrowableArray<const char*>* array = new GrowableArray<const char*>(0);
return array;
}
virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() {
GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo*>(0);
return array;
}
static void parse_and_execute(DCmdSource source, outputStream* out, const char* cmdline,
char delim, TRAPS);
};
class DCmdWithParser : public DCmd {
protected:
DCmdParser _dcmdparser;
public:
DCmdWithParser (outputStream *output, bool heap=false) : DCmd(output, heap) { }
static const char* name() { return "No Name";}
static const char* description() { return "No Help";}
static const char* disabled_message() { return "Diagnostic command currently disabled"; }
static const char* impact() { return "Low: No impact"; }
static const JavaPermission permission() {JavaPermission p = {NULL, NULL, NULL}; return p; }
static int num_arguments() { return 0; }
virtual void parse(CmdLine *line, char delim, TRAPS);
virtual void execute(DCmdSource source, TRAPS) { }
virtual void reset(TRAPS);
virtual void cleanup();
virtual void print_help(const char* name);
virtual GrowableArray<const char*>* argument_name_array();
virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array();
};
class DCmdMark : public StackObj {
DCmd* _ref;
public:
DCmdMark(DCmd* cmd) { _ref = cmd; }
~DCmdMark() {
if (_ref != NULL) {
_ref->cleanup();
if (_ref->is_heap_allocated()) {
delete _ref;
}
}
}
};
class DCmdFactory: public CHeapObj<mtInternal> {
private:
static Mutex* _dcmdFactory_lock;
static bool _send_jmx_notification;
static bool _has_pending_jmx_notification;
DCmdFactory* _next;
bool _enabled;
bool _hidden;
uint32_t _export_flags;
int _num_arguments;
static DCmdFactory* _DCmdFactoryList;
public:
DCmdFactory(int num_arguments, uint32_t flags, bool enabled, bool hidden) {
_next = NULL;
_enabled = enabled;
_hidden = hidden;
_export_flags = flags;
_num_arguments = num_arguments;
}
bool is_enabled() const { return _enabled; }
void set_enabled(bool b) { _enabled = b; }
bool is_hidden() const { return _hidden; }
void set_hidden(bool b) { _hidden = b; }
uint32_t export_flags() { return _export_flags; }
void set_export_flags(uint32_t f) { _export_flags = f; }
int num_arguments() { return _num_arguments; }
DCmdFactory* next() { return _next; }
virtual DCmd* create_Cheap_instance(outputStream* output) = 0;
virtual DCmd* create_resource_instance(outputStream* output) = 0;
virtual const char* name() const = 0;
virtual const char* description() const = 0;
virtual const char* impact() const = 0;
virtual const JavaPermission permission() const = 0;
virtual const char* disabled_message() const = 0;
static int register_DCmdFactory(DCmdFactory* factory);
static DCmdFactory* factory(DCmdSource source, const char* cmd, size_t len);
static DCmd* create_global_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
static DCmd* create_local_DCmd(DCmdSource source, CmdLine &line, outputStream* out, TRAPS);
static GrowableArray<const char*>* DCmd_list(DCmdSource source);
static GrowableArray<DCmdInfo*>* DCmdInfo_list(DCmdSource source);
static void set_jmx_notification_enabled(bool enabled) {
_send_jmx_notification = enabled;
}
static void push_jmx_notification_request();
static bool has_pending_jmx_notification() { return _has_pending_jmx_notification; }
static void send_notification(TRAPS);
private:
static void send_notification_internal(TRAPS);
friend class HelpDCmd;
};
template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory {
public:
DCmdFactoryImpl(uint32_t flags, bool enabled, bool hidden) :
DCmdFactory(DCmdClass::num_arguments(), flags, enabled, hidden) { }
virtual DCmd* create_Cheap_instance(outputStream* output) {
return new (ResourceObj::C_HEAP, mtInternal) DCmdClass(output, true);
}
virtual DCmd* create_resource_instance(outputStream* output) {
return new DCmdClass(output, false);
}
virtual const char* name() const {
return DCmdClass::name();
}
virtual const char* description() const {
return DCmdClass::description();
}
virtual const char* impact() const {
return DCmdClass::impact();
}
virtual const JavaPermission permission() const {
return DCmdClass::permission();
}
virtual const char* disabled_message() const {
return DCmdClass::disabled_message();
}
};
class DCmdRegistrant : public AllStatic {
private:
static void register_dcmds();
static void register_dcmds_ext();
friend class Management;
};
#endif // SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
C:\hotspot-69087d08d473\src\share\vm/services/dtraceAttacher.cpp
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/dtraceAttacher.hpp"
#ifdef SOLARIS
class VM_DeoptimizeTheWorld : public VM_Operation {
public:
VMOp_Type type() const {
return VMOp_DeoptimizeTheWorld;
}
void doit() {
CodeCache::mark_all_nmethods_for_deoptimization();
ResourceMark rm;
DeoptimizationMarker dm;
Deoptimization::deoptimize_dependents();
CodeCache::make_marked_nmethods_not_entrant();
}
};
static void set_bool_flag(const char* flag, bool value) {
CommandLineFlags::boolAtPut((char*)flag, strlen(flag), &value,
Flag::ATTACH_ON_DEMAND);
}
void DTrace::enable_dprobes(int probes) {
bool changed = false;
if (!DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) {
set_bool_flag("DTraceAllocProbes", true);
changed = true;
}
if (!DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) {
set_bool_flag("DTraceMethodProbes", true);
changed = true;
}
if (!DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) {
set_bool_flag("DTraceMonitorProbes", true);
changed = true;
}
if (changed) {
VM_DeoptimizeTheWorld op;
VMThread::execute(&op);
}
}
void DTrace::disable_dprobes(int probes) {
bool changed = false;
if (DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) {
set_bool_flag("DTraceAllocProbes", false);
changed = true;
}
if (DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) {
set_bool_flag("DTraceMethodProbes", false);
changed = true;
}
if (DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) {
set_bool_flag("DTraceMonitorProbes", false);
changed = true;
}
if (changed) {
VM_DeoptimizeTheWorld op;
VMThread::execute(&op);
}
}
void DTrace::detach_all_clients() {
if (ExtendedDTraceProbes) {
enable_dprobes(DTRACE_ALL_PROBES);
} else {
disable_dprobes(DTRACE_ALL_PROBES);
}
}
void DTrace::set_extended_dprobes(bool flag) {
set_bool_flag("ExtendedDTraceProbes", flag);
if (flag) {
enable_dprobes(DTRACE_ALL_PROBES);
} else {
disable_dprobes(DTRACE_ALL_PROBES);
}
}
void DTrace::set_monitor_dprobes(bool flag) {
set_bool_flag("DTraceMonitorProbes", flag);
}
#endif /* SOLARIS */
C:\hotspot-69087d08d473\src\share\vm/services/dtraceAttacher.hpp
#ifndef SHARE_VM_SERVICES_DTRACEATTACHER_HPP
#define SHARE_VM_SERVICES_DTRACEATTACHER_HPP
#define DTRACE_ALLOC_PROBES 0x1
#define DTRACE_METHOD_PROBES 0x2
#define DTRACE_MONITOR_PROBES 0x4
#define DTRACE_ALL_PROBES (DTRACE_ALLOC_PROBES | \
DTRACE_METHOD_PROBES | \
DTRACE_MONITOR_PROBES)
class DTrace : public AllStatic {
private:
static void disable_dprobes(int probe_types);
public:
static void enable_dprobes(int probe_types);
static void detach_all_clients();
static void set_extended_dprobes(bool value);
static void set_monitor_dprobes(bool value);
};
#endif // SHARE_VM_SERVICES_DTRACEATTACHER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/g1MemoryPool.cpp
#include "precompiled.hpp"
#include "gc_implementation/g1/g1CollectedHeap.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
#include "gc_implementation/g1/heapRegion.hpp"
#include "services/g1MemoryPool.hpp"
G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h,
const char* name,
size_t init_size,
size_t max_size,
bool support_usage_threshold) :
_g1mm(g1h->g1mm()), CollectedMemoryPool(name,
MemoryPool::Heap,
init_size,
max_size,
support_usage_threshold) {
assert(UseG1GC, "sanity");
}
G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Eden Space",
g1h->g1mm()->eden_space_committed(), /* init_size */
_undefined_max,
false /* support_usage_threshold */) { }
MemoryUsage G1EdenPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
size_t committed = _g1mm->eden_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Survivor Space",
g1h->g1mm()->survivor_space_committed(), /* init_size */
_undefined_max,
false /* support_usage_threshold */) { }
MemoryUsage G1SurvivorPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
size_t committed = _g1mm->survivor_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Old Gen",
g1h->g1mm()->old_space_committed(), /* init_size */
g1h->g1mm()->old_gen_max(),
true /* support_usage_threshold */) { }
MemoryUsage G1OldGenPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
size_t committed = _g1mm->old_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
C:\hotspot-69087d08d473\src\share\vm/services/g1MemoryPool.hpp
#ifndef SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
#define SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1MonitoringSupport.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryUsage.hpp"
#endif // INCLUDE_ALL_GCS
class G1MemoryPoolSuper : public CollectedMemoryPool {
protected:
const static size_t _undefined_max = (size_t) -1;
G1MonitoringSupport* _g1mm;
G1MemoryPoolSuper(G1CollectedHeap* g1h,
const char* name,
size_t init_size,
size_t max_size,
bool support_usage_threshold);
};
class G1EdenPool : public G1MemoryPoolSuper {
public:
G1EdenPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
return _g1mm->eden_space_used();
}
size_t max_size() const {
return _undefined_max;
}
MemoryUsage get_memory_usage();
};
class G1SurvivorPool : public G1MemoryPoolSuper {
public:
G1SurvivorPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
return _g1mm->survivor_space_used();
}
size_t max_size() const {
return _undefined_max;
}
MemoryUsage get_memory_usage();
};
class G1OldGenPool : public G1MemoryPoolSuper {
public:
G1OldGenPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
return _g1mm->old_space_used();
}
size_t max_size() const {
return _g1mm->old_gen_max();
}
MemoryUsage get_memory_usage();
};
#endif // SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
C:\hotspot-69087d08d473\src\share\vm/services/gcNotifier.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/gcNotifier.hpp"
#include "services/management.hpp"
#include "services/memoryService.hpp"
#include "memoryManager.hpp"
#include "memory/oopFactory.hpp"
GCNotificationRequest *GCNotifier::first_request = NULL;
GCNotificationRequest *GCNotifier::last_request = NULL;
void GCNotifier::pushNotification(GCMemoryManager *mgr, const char *action, const char *cause) {
int num_pools = MemoryService::num_memory_pools();
GCStatInfo* stat = new(ResourceObj::C_HEAP, mtGC) GCStatInfo(num_pools);
mgr->get_last_gc_stat(stat);
GCNotificationRequest *request = new GCNotificationRequest(os::javaTimeMillis(),mgr,action,cause,stat);
addRequest(request);
}
void GCNotifier::addRequest(GCNotificationRequest *request) {
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
if(first_request == NULL) {
first_request = request;
} else {
last_request->next = request;
}
last_request = request;
Service_lock->notify_all();
}
GCNotificationRequest *GCNotifier::getRequest() {
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
GCNotificationRequest *request = first_request;
if(first_request != NULL) {
first_request = first_request->next;
}
return request;
}
bool GCNotifier::has_event() {
return first_request != NULL;
}
static Handle getGcInfoBuilder(GCMemoryManager *gcManager,TRAPS) {
Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK_NH);
instanceKlassHandle gcMBeanKlass (THREAD, k);
instanceOop i = gcManager->get_memory_manager_instance(THREAD);
instanceHandle ih(THREAD, i);
JavaValue result(T_OBJECT);
JavaCallArguments args(ih);
JavaCalls::call_virtual(&result,
gcMBeanKlass,
vmSymbols::getGcInfoBuilder_name(),
vmSymbols::getGcInfoBuilder_signature(),
&args,
CHECK_NH);
return Handle(THREAD,(oop)result.get_jobject());
}
static Handle createGcInfo(GCMemoryManager *gcManager, GCStatInfo *gcStatInfo,TRAPS) {
Klass* mu_klass = Management::java_lang_management_MemoryUsage_klass(CHECK_NH);
instanceKlassHandle mu_kh(THREAD, mu_klass);
objArrayOop bu = oopFactory::new_objArray(mu_kh(), MemoryService::num_memory_pools(), CHECK_NH);
objArrayHandle usage_before_gc_ah(THREAD, bu);
objArrayOop au = oopFactory::new_objArray(mu_kh(), MemoryService::num_memory_pools(), CHECK_NH);
objArrayHandle usage_after_gc_ah(THREAD, au);
for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
Handle before_usage = MemoryService::create_MemoryUsage_obj(gcStatInfo->before_gc_usage_for_pool(i), CHECK_NH);
Handle after_usage;
MemoryUsage u = gcStatInfo->after_gc_usage_for_pool(i);
if (u.max_size() == 0 && u.used() > 0) {
MemoryUsage usage(u.init_size(), u.used(), u.committed(), (size_t)-1);
after_usage = MemoryService::create_MemoryUsage_obj(usage, CHECK_NH);
} else {
after_usage = MemoryService::create_MemoryUsage_obj(u, CHECK_NH);
}
usage_before_gc_ah->obj_at_put(i, before_usage());
usage_after_gc_ah->obj_at_put(i, after_usage());
}
objArrayOop extra_args_array = oopFactory::new_objArray(SystemDictionary::Integer_klass(), 1, CHECK_NH);
objArrayHandle extra_array (THREAD, extra_args_array);
Klass* itKlass = SystemDictionary::Integer_klass();
instanceKlassHandle intK(THREAD, itKlass);
instanceHandle extra_arg_val = intK->allocate_instance_handle(CHECK_NH);
{
JavaValue res(T_VOID);
JavaCallArguments argsInt;
argsInt.push_oop(extra_arg_val);
argsInt.push_int(gcManager->num_gc_threads());
JavaCalls::call_special(&res,
intK,
vmSymbols::object_initializer_name(),
vmSymbols::int_void_signature(),
&argsInt,
CHECK_NH);
}
extra_array->obj_at_put(0,extra_arg_val());
Klass* gcInfoklass = Management::com_sun_management_GcInfo_klass(CHECK_NH);
instanceKlassHandle ik(THREAD, gcInfoklass);
Handle gcInfo_instance = ik->allocate_instance_handle(CHECK_NH);
JavaValue constructor_result(T_VOID);
JavaCallArguments constructor_args(16);
constructor_args.push_oop(gcInfo_instance);
constructor_args.push_oop(getGcInfoBuilder(gcManager,THREAD));
constructor_args.push_long(gcStatInfo->gc_index());
constructor_args.push_long(Management::ticks_to_ms(gcStatInfo->start_time()));
constructor_args.push_long(Management::ticks_to_ms(gcStatInfo->end_time()));
constructor_args.push_oop(usage_before_gc_ah);
constructor_args.push_oop(usage_after_gc_ah);
constructor_args.push_oop(extra_array);
JavaCalls::call_special(&constructor_result,
ik,
vmSymbols::object_initializer_name(),
vmSymbols::com_sun_management_GcInfo_constructor_signature(),
&constructor_args,
CHECK_NH);
return Handle(gcInfo_instance());
}
void GCNotifier::sendNotification(TRAPS) {
GCNotifier::sendNotificationInternal(THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
}
class NotificationMark : public StackObj {
GCNotificationRequest* _request;
public:
NotificationMark(GCNotificationRequest* r) {
_request = r;
}
~NotificationMark() {
assert(_request != NULL, "Sanity check");
delete _request;
}
};
void GCNotifier::sendNotificationInternal(TRAPS) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
GCNotificationRequest *request = getRequest();
if (request != NULL) {
NotificationMark nm(request);
Handle objGcInfo = createGcInfo(request->gcManager, request->gcStatInfo, CHECK);
Handle objName = java_lang_String::create_from_str(request->gcManager->name(), CHECK);
Handle objAction = java_lang_String::create_from_str(request->gcAction, CHECK);
Handle objCause = java_lang_String::create_from_str(request->gcCause, CHECK);
Klass* k = Management::sun_management_GarbageCollectorImpl_klass(CHECK);
instanceKlassHandle gc_mbean_klass(THREAD, k);
instanceOop gc_mbean = request->gcManager->get_memory_manager_instance(THREAD);
instanceHandle gc_mbean_h(THREAD, gc_mbean);
if (!gc_mbean_h->is_a(k)) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"This GCMemoryManager doesn't have a GarbageCollectorMXBean");
}
JavaValue result(T_VOID);
JavaCallArguments args(gc_mbean_h);
args.push_long(request->timestamp);
args.push_oop(objName);
args.push_oop(objAction);
args.push_oop(objCause);
args.push_oop(objGcInfo);
JavaCalls::call_virtual(&result,
gc_mbean_klass,
vmSymbols::createGCNotification_name(),
vmSymbols::createGCNotification_signature(),
&args,
CHECK);
}
}
C:\hotspot-69087d08d473\src\share\vm/services/gcNotifier.hpp
#ifndef SHARE_VM_SERVICES_GCNOTIFIER_HPP
#define SHARE_VM_SERVICES_GCNOTIFIER_HPP
#include "memory/allocation.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryService.hpp"
#include "services/memoryManager.hpp"
class GCNotificationRequest : public CHeapObj<mtInternal> {
friend class GCNotifier;
GCNotificationRequest *next;
jlong timestamp;
GCMemoryManager *gcManager;
const char *gcAction;
const char *gcCause;
GCStatInfo *gcStatInfo;
public:
GCNotificationRequest(jlong ts, GCMemoryManager *manager, const char*action, const char *cause,GCStatInfo *info) {
next = NULL;
timestamp = ts;
gcManager = manager;
gcAction = action;
gcCause = cause;
gcStatInfo = info;
}
~GCNotificationRequest() {
delete gcStatInfo;
}
};
class GCNotifier : public AllStatic {
friend class ServiceThread;
private:
static GCNotificationRequest *first_request;
static GCNotificationRequest *last_request;
static void addRequest(GCNotificationRequest *request);
static GCNotificationRequest *getRequest();
static void sendNotificationInternal(TRAPS);
public:
static void pushNotification(GCMemoryManager *manager, const char *action, const char *cause);
static bool has_event();
static void sendNotification(TRAPS);
};
#endif // SHARE_VM_SERVICES_GCNOTIFIER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/heapDumper.cpp
#include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/universe.hpp"
#include "oops/objArrayKlass.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
#include "runtime/vm_operations.hpp"
#include "services/heapDumper.hpp"
#include "services/threadService.hpp"
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"
#endif // INCLUDE_ALL_GCS
typedef enum {
HPROF_UTF8 = 0x01,
HPROF_LOAD_CLASS = 0x02,
HPROF_UNLOAD_CLASS = 0x03,
HPROF_FRAME = 0x04,
HPROF_TRACE = 0x05,
HPROF_ALLOC_SITES = 0x06,
HPROF_HEAP_SUMMARY = 0x07,
HPROF_START_THREAD = 0x0A,
HPROF_END_THREAD = 0x0B,
HPROF_HEAP_DUMP = 0x0C,
HPROF_CPU_SAMPLES = 0x0D,
HPROF_CONTROL_SETTINGS = 0x0E,
HPROF_HEAP_DUMP_SEGMENT = 0x1C,
HPROF_HEAP_DUMP_END = 0x2C,
HPROF_ARRAY_OBJECT = 0x01,
HPROF_NORMAL_OBJECT = 0x02,
HPROF_BOOLEAN = 0x04,
HPROF_CHAR = 0x05,
HPROF_FLOAT = 0x06,
HPROF_DOUBLE = 0x07,
HPROF_BYTE = 0x08,
HPROF_SHORT = 0x09,
HPROF_INT = 0x0A,
HPROF_LONG = 0x0B,
HPROF_GC_ROOT_UNKNOWN = 0xFF,
HPROF_GC_ROOT_JNI_GLOBAL = 0x01,
HPROF_GC_ROOT_JNI_LOCAL = 0x02,
HPROF_GC_ROOT_JAVA_FRAME = 0x03,
HPROF_GC_ROOT_NATIVE_STACK = 0x04,
HPROF_GC_ROOT_STICKY_CLASS = 0x05,
HPROF_GC_ROOT_THREAD_BLOCK = 0x06,
HPROF_GC_ROOT_MONITOR_USED = 0x07,
HPROF_GC_ROOT_THREAD_OBJ = 0x08,
HPROF_GC_CLASS_DUMP = 0x20,
HPROF_GC_INSTANCE_DUMP = 0x21,
HPROF_GC_OBJ_ARRAY_DUMP = 0x22,
HPROF_GC_PRIM_ARRAY_DUMP = 0x23
} hprofTag;
enum {
STACK_TRACE_ID = 1,
INITIAL_CLASS_COUNT = 200
};
class DumpWriter : public StackObj {
private:
enum {
io_buffer_size = 8*M
};
int _fd; // file descriptor (-1 if dump file not open)
julong _bytes_written; // number of byte written to dump file
char* _buffer; // internal buffer
size_t _size;
size_t _pos;
jlong _dump_start;
char* _error; // error message when I/O fails
void set_file_descriptor(int fd) { _fd = fd; }
int file_descriptor() const { return _fd; }
char* buffer() const { return _buffer; }
size_t buffer_size() const { return _size; }
size_t position() const { return _pos; }
void set_position(size_t pos) { _pos = pos; }
void set_error(const char* error) { _error = (char*)os::strdup(error); }
void write_internal(void* s, size_t len);
public:
DumpWriter(const char* path);
~DumpWriter();
void close();
bool is_open() const { return file_descriptor() >= 0; }
void flush();
jlong dump_start() const { return _dump_start; }
void set_dump_start(jlong pos);
julong current_record_length();
julong bytes_written() const { return _bytes_written; }
void adjust_bytes_written(jlong n) { _bytes_written += n; }
size_t bytes_unwritten() const { return position(); }
char* error() const { return _error; }
jlong current_offset();
void seek_to_offset(jlong pos);
void write_raw(void* s, size_t len);
void write_u1(u1 x) { write_raw((void*)&x, 1); }
void write_u2(u2 x);
void write_u4(u4 x);
void write_u8(u8 x);
void write_objectID(oop o);
void write_symbolID(Symbol* o);
void write_classID(Klass* k);
void write_id(u4 x);
};
DumpWriter::DumpWriter(const char* path) {
_size = io_buffer_size;
do {
_buffer = (char*)os::malloc(_size, mtInternal);
if (_buffer == NULL) {
_size = _size >> 1;
}
} while (_buffer == NULL && _size > 0);
assert((_size > 0 && _buffer != NULL) || (_size == 0 && _buffer == NULL), "sanity check");
_pos = 0;
_error = NULL;
_bytes_written = 0L;
_dump_start = (jlong)-1;
_fd = os::create_binary_file(path, false); // don't replace existing file
if (_fd < 0) {
_error = (char*)os::strdup(strerror(errno));
}
}
DumpWriter::~DumpWriter() {
if (is_open()) {
close();
}
if (_buffer != NULL) os::free(_buffer);
if (_error != NULL) os::free(_error);
}
void DumpWriter::close() {
if (is_open()) {
flush();
::close(file_descriptor());
set_file_descriptor(-1);
}
}
void DumpWriter::set_dump_start(jlong pos) {
_dump_start = pos;
}
julong DumpWriter::current_record_length() {
if (is_open()) {
julong dump_end = bytes_written() + bytes_unwritten();
assert(dump_end == (size_t)current_offset(), "checking");
julong dump_len = dump_end - dump_start() - 4;
return dump_len;
}
return 0;
}
void DumpWriter::write_internal(void* s, size_t len) {
if (is_open()) {
const char* pos = (char*)s;
ssize_t n = 0;
while (len > 0) {
uint tmp = (uint)MIN2(len, (size_t)UINT_MAX);
n = ::write(file_descriptor(), pos, tmp);
if (n < 0) {
set_error(strerror(errno));
::close(file_descriptor());
set_file_descriptor(-1);
return;
}
_bytes_written += n;
pos += n;
len -= n;
}
}
}
void DumpWriter::write_raw(void* s, size_t len) {
if (is_open()) {
if ((position() + len) >= buffer_size()) {
flush();
}
if ((buffer() == NULL) || (len >= buffer_size())) {
write_internal(s, len);
} else {
memcpy(buffer() + position(), s, len);
set_position(position() + len);
}
}
}
void DumpWriter::flush() {
if (is_open() && position() > 0) {
write_internal(buffer(), position());
set_position(0);
}
}
jlong DumpWriter::current_offset() {
if (is_open()) {
jlong offset = os::current_file_offset(file_descriptor());
assert(offset >= 0, "lseek failed");
return offset + position();
} else {
return (jlong)-1;
}
}
void DumpWriter::seek_to_offset(jlong off) {
assert(off >= 0, "bad offset");
flush();
if (is_open()) {
jlong n = os::seek_to_file_offset(file_descriptor(), off);
assert(n >= 0, "lseek failed");
}
}
void DumpWriter::write_u2(u2 x) {
u2 v;
Bytes::put_Java_u2((address)&v, x);
write_raw((void*)&v, 2);
}
void DumpWriter::write_u4(u4 x) {
u4 v;
Bytes::put_Java_u4((address)&v, x);
write_raw((void*)&v, 4);
}
void DumpWriter::write_u8(u8 x) {
u8 v;
Bytes::put_Java_u8((address)&v, x);
write_raw((void*)&v, 8);
}
void DumpWriter::write_objectID(oop o) {
address a = (address)o;
#ifdef _LP64
write_u8((u8)a);
#else
write_u4((u4)a);
#endif
}
void DumpWriter::write_symbolID(Symbol* s) {
address a = (address)((uintptr_t)s);
#ifdef _LP64
write_u8((u8)a);
#else
write_u4((u4)a);
#endif
}
void DumpWriter::write_id(u4 x) {
#ifdef _LP64
write_u8((u8) x);
#else
write_u4(x);
#endif
}
void DumpWriter::write_classID(Klass* k) {
write_objectID(k->java_mirror());
}
class DumperSupport : AllStatic {
public:
static void write_header(DumpWriter* writer, hprofTag tag, u4 len);
static hprofTag sig2tag(Symbol* sig);
static hprofTag type2tag(BasicType type);
static u4 instance_size(Klass* k);
static void dump_float(DumpWriter* writer, jfloat f);
static void dump_double(DumpWriter* writer, jdouble d);
static void dump_field_value(DumpWriter* writer, char type, address addr);
static void dump_static_fields(DumpWriter* writer, Klass* k);
static void dump_instance_fields(DumpWriter* writer, oop o);
static void dump_instance_field_descriptors(DumpWriter* writer, Klass* k);
static void dump_instance(DumpWriter* writer, oop o);
static void dump_class_and_array_classes(DumpWriter* writer, Klass* k);
static void dump_basic_type_array_class(DumpWriter* writer, Klass* k);
static void dump_object_array(DumpWriter* writer, objArrayOop array);
static void dump_prim_array(DumpWriter* writer, typeArrayOop array);
static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci);
static int calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size);
static void write_dump_header(DumpWriter* writer);
static void write_current_dump_record_length(DumpWriter* writer);
static void end_of_dump(DumpWriter* writer);
};
void DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) {
writer->write_u1((u1)tag);
writer->write_u4(0); // current ticks
writer->write_u4(len);
}
hprofTag DumperSupport::sig2tag(Symbol* sig) {
switch (sig->byte_at(0)) {
case JVM_SIGNATURE_CLASS : return HPROF_NORMAL_OBJECT;
case JVM_SIGNATURE_ARRAY : return HPROF_NORMAL_OBJECT;
case JVM_SIGNATURE_BYTE : return HPROF_BYTE;
case JVM_SIGNATURE_CHAR : return HPROF_CHAR;
case JVM_SIGNATURE_FLOAT : return HPROF_FLOAT;
case JVM_SIGNATURE_DOUBLE : return HPROF_DOUBLE;
case JVM_SIGNATURE_INT : return HPROF_INT;
case JVM_SIGNATURE_LONG : return HPROF_LONG;
case JVM_SIGNATURE_SHORT : return HPROF_SHORT;
case JVM_SIGNATURE_BOOLEAN : return HPROF_BOOLEAN;
default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE;
}
}
hprofTag DumperSupport::type2tag(BasicType type) {
switch (type) {
case T_BYTE : return HPROF_BYTE;
case T_CHAR : return HPROF_CHAR;
case T_FLOAT : return HPROF_FLOAT;
case T_DOUBLE : return HPROF_DOUBLE;
case T_INT : return HPROF_INT;
case T_LONG : return HPROF_LONG;
case T_SHORT : return HPROF_SHORT;
case T_BOOLEAN : return HPROF_BOOLEAN;
default : ShouldNotReachHere(); /* to shut up compiler */ return HPROF_BYTE;
}
}
void DumperSupport::dump_float(DumpWriter* writer, jfloat f) {
if (g_isnan(f)) {
writer->write_u4(0x7fc00000); // collapsing NaNs
} else {
union {
int i;
float f;
} u;
u.f = (float)f;
writer->write_u4((u4)u.i);
}
}
void DumperSupport::dump_double(DumpWriter* writer, jdouble d) {
union {
jlong l;
double d;
} u;
if (g_isnan(d)) { // collapsing NaNs
u.l = (jlong)(0x7ff80000);
u.l = (u.l << 32);
} else {
u.d = (double)d;
}
writer->write_u8((u8)u.l);
}
void DumperSupport::dump_field_value(DumpWriter* writer, char type, address addr) {
switch (type) {
case JVM_SIGNATURE_CLASS :
case JVM_SIGNATURE_ARRAY : {
oop o;
if (UseCompressedOops) {
o = oopDesc::load_decode_heap_oop((narrowOop*)addr);
} else {
o = oopDesc::load_decode_heap_oop((oop*)addr);
}
assert(o->is_oop_or_null(), "should always be an oop");
writer->write_objectID(o);
break;
}
case JVM_SIGNATURE_BYTE : {
jbyte* b = (jbyte*)addr;
writer->write_u1((u1)*b);
break;
}
case JVM_SIGNATURE_CHAR : {
jchar* c = (jchar*)addr;
writer->write_u2((u2)*c);
break;
}
case JVM_SIGNATURE_SHORT : {
jshort* s = (jshort*)addr;
writer->write_u2((u2)*s);
break;
}
case JVM_SIGNATURE_FLOAT : {
jfloat* f = (jfloat*)addr;
dump_float(writer, *f);
break;
}
case JVM_SIGNATURE_DOUBLE : {
jdouble* f = (jdouble*)addr;
dump_double(writer, *f);
break;
}
case JVM_SIGNATURE_INT : {
jint* i = (jint*)addr;
writer->write_u4((u4)*i);
break;
}
case JVM_SIGNATURE_LONG : {
jlong* l = (jlong*)addr;
writer->write_u8((u8)*l);
break;
}
case JVM_SIGNATURE_BOOLEAN : {
jboolean* b = (jboolean*)addr;
writer->write_u1((u1)*b);
break;
}
default : ShouldNotReachHere();
}
}
u4 DumperSupport::instance_size(Klass* k) {
HandleMark hm;
instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
u4 size = 0;
for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) {
if (!fld.access_flags().is_static()) {
Symbol* sig = fld.signature();
switch (sig->byte_at(0)) {
case JVM_SIGNATURE_CLASS :
case JVM_SIGNATURE_ARRAY : size += oopSize; break;
case JVM_SIGNATURE_BYTE :
case JVM_SIGNATURE_BOOLEAN : size += 1; break;
case JVM_SIGNATURE_CHAR :
case JVM_SIGNATURE_SHORT : size += 2; break;
case JVM_SIGNATURE_INT :
case JVM_SIGNATURE_FLOAT : size += 4; break;
case JVM_SIGNATURE_LONG :
case JVM_SIGNATURE_DOUBLE : size += 8; break;
default : ShouldNotReachHere();
}
}
}
return size;
}
void DumperSupport::dump_static_fields(DumpWriter* writer, Klass* k) {
HandleMark hm;
instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
u2 field_count = 0;
for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) {
if (fldc.access_flags().is_static()) field_count++;
}
oop resolved_references = ikh->constants()->resolved_references_or_null();
if (resolved_references != NULL) {
field_count++;
InstanceKlass* prev = ikh->previous_versions();
while (prev != NULL && prev->constants()->resolved_references_or_null() != NULL) {
field_count++;
prev = prev->previous_versions();
}
}
oop init_lock = ikh->init_lock();
if (init_lock != NULL) {
field_count++;
}
writer->write_u2(field_count);
for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) {
if (fld.access_flags().is_static()) {
Symbol* sig = fld.signature();
writer->write_symbolID(fld.name()); // name
writer->write_u1(sig2tag(sig)); // type
int offset = fld.offset();
address addr = (address)ikh->java_mirror() + offset;
dump_field_value(writer, sig->byte_at(0), addr);
}
}
if (resolved_references != NULL) {
writer->write_symbolID(vmSymbols::resolved_references_name()); // name
writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type
writer->write_objectID(resolved_references);
InstanceKlass* prev = ikh->previous_versions();
while (prev != NULL && prev->constants()->resolved_references_or_null() != NULL) {
writer->write_symbolID(vmSymbols::resolved_references_name()); // name
writer->write_u1(sig2tag(vmSymbols::object_array_signature())); // type
writer->write_objectID(prev->constants()->resolved_references());
prev = prev->previous_versions();
}
}
if (init_lock != NULL) {
writer->write_symbolID(vmSymbols::init_lock_name()); // name
writer->write_u1(sig2tag(vmSymbols::int_array_signature())); // type
writer->write_objectID(init_lock);
}
}
void DumperSupport::dump_instance_fields(DumpWriter* writer, oop o) {
HandleMark hm;
instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), o->klass());
for (FieldStream fld(ikh, false, false); !fld.eos(); fld.next()) {
if (!fld.access_flags().is_static()) {
Symbol* sig = fld.signature();
address addr = (address)o + fld.offset();
dump_field_value(writer, sig->byte_at(0), addr);
}
}
}
void DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, Klass* k) {
HandleMark hm;
instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
u2 field_count = 0;
for (FieldStream fldc(ikh, true, true); !fldc.eos(); fldc.next()) {
if (!fldc.access_flags().is_static()) field_count++;
}
writer->write_u2(field_count);
for (FieldStream fld(ikh, true, true); !fld.eos(); fld.next()) {
if (!fld.access_flags().is_static()) {
Symbol* sig = fld.signature();
writer->write_symbolID(fld.name()); // name
writer->write_u1(sig2tag(sig)); // type
}
}
}
void DumperSupport::dump_instance(DumpWriter* writer, oop o) {
Klass* k = o->klass();
writer->write_u1(HPROF_GC_INSTANCE_DUMP);
writer->write_objectID(o);
writer->write_u4(STACK_TRACE_ID);
writer->write_classID(k);
writer->write_u4(instance_size(k) );
dump_instance_fields(writer, o);
}
void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) {
Klass* klass = k;
InstanceKlass* ik = InstanceKlass::cast(k);
if (!ik->is_loaded()) {
return;
}
writer->write_u1(HPROF_GC_CLASS_DUMP);
writer->write_classID(ik);
writer->write_u4(STACK_TRACE_ID);
Klass* java_super = ik->java_super();
if (java_super == NULL) {
writer->write_objectID(oop(NULL));
} else {
writer->write_classID(java_super);
}
writer->write_objectID(ik->class_loader());
writer->write_objectID(ik->signers());
writer->write_objectID(ik->protection_domain());
writer->write_objectID(oop(NULL));
writer->write_objectID(oop(NULL));
writer->write_u4(DumperSupport::instance_size(k));
writer->write_u2(0);
dump_static_fields(writer, k);
dump_instance_field_descriptors(writer, k);
k = klass->array_klass_or_null();
while (k != NULL) {
Klass* klass = k;
assert(klass->oop_is_objArray(), "not an ObjArrayKlass");
writer->write_u1(HPROF_GC_CLASS_DUMP);
writer->write_classID(klass);
writer->write_u4(STACK_TRACE_ID);
java_super = klass->java_super();
assert(java_super != NULL, "checking");
writer->write_classID(java_super);
writer->write_objectID(ik->class_loader());
writer->write_objectID(ik->signers());
writer->write_objectID(ik->protection_domain());
writer->write_objectID(oop(NULL)); // reserved
writer->write_objectID(oop(NULL));
writer->write_u4(0); // instance size
writer->write_u2(0); // constant pool
writer->write_u2(0); // static fields
writer->write_u2(0); // instance fields
k = klass->array_klass_or_null();
}
}
void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) {
while (k != NULL) {
Klass* klass = k;
writer->write_u1(HPROF_GC_CLASS_DUMP);
writer->write_classID(klass);
writer->write_u4(STACK_TRACE_ID);
Klass* java_super = klass->java_super();
assert(java_super != NULL, "checking");
writer->write_classID(java_super);
writer->write_objectID(oop(NULL)); // loader
writer->write_objectID(oop(NULL)); // signers
writer->write_objectID(oop(NULL)); // protection domain
writer->write_objectID(oop(NULL)); // reserved
writer->write_objectID(oop(NULL));
writer->write_u4(0); // instance size
writer->write_u2(0); // constant pool
writer->write_u2(0); // static fields
writer->write_u2(0); // instance fields
k = klass->array_klass_or_null();
}
}
int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size) {
BasicType type = ArrayKlass::cast(array->klass())->element_type();
assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type");
int length = array->length();
int type_size;
if (type == T_OBJECT) {
type_size = sizeof(address);
} else {
type_size = type2aelembytes(type);
}
size_t length_in_bytes = (size_t)length * type_size;
julong current_record_length = writer->current_record_length();
if (current_record_length > 0 &&
(current_record_length + header_size + length_in_bytes) > max_juint) {
write_current_dump_record_length(writer);
write_dump_header(writer);
current_record_length = 0;
}
uint max_bytes = max_juint - (header_size + current_record_length);
if (length_in_bytes > max_bytes) {
length = max_bytes / type_size;
length_in_bytes = (size_t)length * type_size;
warning("cannot dump array of type %s[] with length %d; truncating to length %d",
type2name_tab[type], array->length(), length);
}
return length;
}
void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) {
short header_size = 1 + 2 * 4 + 2 * sizeof(address);
int length = calculate_array_max_length(writer, array, header_size);
writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP);
writer->write_objectID(array);
writer->write_u4(STACK_TRACE_ID);
writer->write_u4(length);
writer->write_classID(array->klass());
for (int index = 0; index < length; index++) {
oop o = array->obj_at(index);
writer->write_objectID(o);
}
}
#define WRITE_ARRAY(Array, Type, Size, Length) \
for (int i = 0; i < Length; i++) { writer->write_##Size((Size)array->Type##_at(i)); }
void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) {
BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
short header_size = 2 * 1 + 2 * 4 + sizeof(address);
int length = calculate_array_max_length(writer, array, header_size);
int type_size = type2aelembytes(type);
u4 length_in_bytes = (u4)length * type_size;
writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP);
writer->write_objectID(array);
writer->write_u4(STACK_TRACE_ID);
writer->write_u4(length);
writer->write_u1(type2tag(type));
if (length == 0) {
return;
}
switch (type) {
case T_INT : {
if (Bytes::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, int, u4, length);
} else {
writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes);
}
break;
}
case T_BYTE : {
writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes);
break;
}
case T_CHAR : {
if (Bytes::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, char, u2, length);
} else {
writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes);
}
break;
}
case T_SHORT : {
if (Bytes::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, short, u2, length);
} else {
writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes);
}
break;
}
case T_BOOLEAN : {
if (Bytes::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, bool, u1, length);
} else {
writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes);
}
break;
}
case T_LONG : {
if (Bytes::is_Java_byte_ordering_different()) {
WRITE_ARRAY(array, long, u8, length);
} else {
writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes);
}
break;
}
case T_FLOAT : {
for (int i = 0; i < length; i++) {
dump_float(writer, array->float_at(i));
}
break;
}
case T_DOUBLE : {
for (int i = 0; i < length; i++) {
dump_double(writer, array->double_at(i));
}
break;
}
default : ShouldNotReachHere();
}
}
void DumperSupport::dump_stack_frame(DumpWriter* writer,
int frame_serial_num,
int class_serial_num,
Method* m,
int bci) {
int line_number;
if (m->is_native()) {
line_number = -3; // native frame
} else {
line_number = m->line_number_from_bci(bci);
}
write_header(writer, HPROF_FRAME, 4*oopSize + 2*sizeof(u4));
writer->write_id(frame_serial_num); // frame serial number
writer->write_symbolID(m->name()); // method's name
writer->write_symbolID(m->signature()); // method's signature
assert(m->method_holder()->oop_is_instance(), "not InstanceKlass");
writer->write_symbolID(m->method_holder()->source_file_name()); // source file name
writer->write_u4(class_serial_num); // class serial number
writer->write_u4((u4) line_number); // line number
}
class SymbolTableDumper : public SymbolClosure {
private:
DumpWriter* _writer;
DumpWriter* writer() const { return _writer; }
public:
SymbolTableDumper(DumpWriter* writer) { _writer = writer; }
void do_symbol(Symbol** p);
};
void SymbolTableDumper::do_symbol(Symbol** p) {
ResourceMark rm;
Symbol* sym = load_symbol(p);
int len = sym->utf8_length();
if (len > 0) {
char* s = sym->as_utf8();
DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len);
writer()->write_symbolID(sym);
writer()->write_raw(s, len);
}
}
class JNILocalsDumper : public OopClosure {
private:
DumpWriter* _writer;
u4 _thread_serial_num;
int _frame_num;
DumpWriter* writer() const { return _writer; }
public:
JNILocalsDumper(DumpWriter* writer, u4 thread_serial_num) {
_writer = writer;
_thread_serial_num = thread_serial_num;
_frame_num = -1; // default - empty stack
}
void set_frame_number(int n) { _frame_num = n; }
void do_oop(oop* obj_p);
void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
void JNILocalsDumper::do_oop(oop* obj_p) {
oop o = *obj_p;
if (o != NULL && o != JNIHandles::deleted_handle()) {
writer()->write_u1(HPROF_GC_ROOT_JNI_LOCAL);
writer()->write_objectID(o);
writer()->write_u4(_thread_serial_num);
writer()->write_u4((u4)_frame_num);
}
}
class JNIGlobalsDumper : public OopClosure {
private:
DumpWriter* _writer;
DumpWriter* writer() const { return _writer; }
public:
JNIGlobalsDumper(DumpWriter* writer) {
_writer = writer;
}
void do_oop(oop* obj_p);
void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
void JNIGlobalsDumper::do_oop(oop* obj_p) {
oop o = *obj_p;
if (o == NULL || o == JNIHandles::deleted_handle()) return;
if (o->is_instance() || o->is_objArray() || o->is_typeArray()) {
writer()->write_u1(HPROF_GC_ROOT_JNI_GLOBAL);
writer()->write_objectID(o);
writer()->write_objectID((oopDesc*)obj_p); // global ref ID
}
};
class MonitorUsedDumper : public OopClosure {
private:
DumpWriter* _writer;
DumpWriter* writer() const { return _writer; }
public:
MonitorUsedDumper(DumpWriter* writer) {
_writer = writer;
}
void do_oop(oop* obj_p) {
writer()->write_u1(HPROF_GC_ROOT_MONITOR_USED);
writer()->write_objectID(*obj_p);
}
void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
};
class StickyClassDumper : public KlassClosure {
private:
DumpWriter* _writer;
DumpWriter* writer() const { return _writer; }
public:
StickyClassDumper(DumpWriter* writer) {
_writer = writer;
}
void do_klass(Klass* k) {
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k);
writer()->write_u1(HPROF_GC_ROOT_STICKY_CLASS);
writer()->write_classID(ik);
}
}
};
class VM_HeapDumper;
class HeapObjectDumper : public ObjectClosure {
private:
VM_HeapDumper* _dumper;
DumpWriter* _writer;
VM_HeapDumper* dumper() { return _dumper; }
DumpWriter* writer() { return _writer; }
void mark_end_of_record();
public:
HeapObjectDumper(VM_HeapDumper* dumper, DumpWriter* writer) {
_dumper = dumper;
_writer = writer;
}
void do_object(oop o);
};
void HeapObjectDumper::do_object(oop o) {
if (o == JNIHandles::deleted_handle()) return;
if (o->klass() == SystemDictionary::Class_klass()) {
if (!java_lang_Class::is_primitive(o)) {
return;
}
}
if (o->is_instance()) {
DumperSupport::dump_instance(writer(), o);
mark_end_of_record();
} else if (o->is_objArray()) {
DumperSupport::dump_object_array(writer(), objArrayOop(o));
mark_end_of_record();
} else if (o->is_typeArray()) {
DumperSupport::dump_prim_array(writer(), typeArrayOop(o));
mark_end_of_record();
}
}
class VM_HeapDumper : public VM_GC_Operation {
private:
static VM_HeapDumper* _global_dumper;
static DumpWriter* _global_writer;
DumpWriter* _local_writer;
JavaThread* _oome_thread;
Method* _oome_constructor;
bool _gc_before_heap_dump;
GrowableArray<Klass*>* _klass_map;
ThreadStackTrace** _stack_traces;
int _num_threads;
static VM_HeapDumper* dumper() { assert(_global_dumper != NULL, "Error"); return _global_dumper; }
static DumpWriter* writer() { assert(_global_writer != NULL, "Error"); return _global_writer; }
void set_global_dumper() {
assert(_global_dumper == NULL, "Error");
_global_dumper = this;
}
void set_global_writer() {
assert(_global_writer == NULL, "Error");
_global_writer = _local_writer;
}
void clear_global_dumper() { _global_dumper = NULL; }
void clear_global_writer() { _global_writer = NULL; }
bool skip_operation() const;
static void do_load_class(Klass* k);
static void do_class_dump(Klass* k);
static void do_basic_type_array_class_dump(Klass* k);
int do_thread(JavaThread* thread, u4 thread_serial_num);
void do_threads();
void add_class_serial_number(Klass* k, int serial_num) {
_klass_map->at_put_grow(serial_num, k);
}
void dump_stack_traces();
public:
VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) :
VM_GC_Operation(0 /* total collections, dummy, ignored */,
GCCause::_heap_dump /* GC Cause */,
0 /* total full collections, dummy, ignored */,
gc_before_heap_dump) {
_local_writer = writer;
_gc_before_heap_dump = gc_before_heap_dump;
_klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true);
_stack_traces = NULL;
_num_threads = 0;
if (oome) {
assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread");
InstanceKlass* oome_ik = InstanceKlass::cast(SystemDictionary::OutOfMemoryError_klass());
_oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(),
vmSymbols::void_method_signature());
_oome_thread = JavaThread::current();
} else {
_oome_thread = NULL;
_oome_constructor = NULL;
}
}
~VM_HeapDumper() {
if (_stack_traces != NULL) {
for (int i=0; i < _num_threads; i++) {
delete _stack_traces[i];
}
FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces, mtInternal);
}
delete _klass_map;
}
VMOp_Type type() const { return VMOp_HeapDumper; }
void check_segment_length();
void doit();
};
VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL;
DumpWriter* VM_HeapDumper::_global_writer = NULL;
bool VM_HeapDumper::skip_operation() const {
return false;
}
void DumperSupport::write_dump_header(DumpWriter* writer) {
if (writer->is_open()) {
writer->write_u1(HPROF_HEAP_DUMP_SEGMENT);
writer->write_u4(0); // current ticks
writer->set_dump_start(writer->current_offset());
writer->write_u4(0);
}
}
void DumperSupport::write_current_dump_record_length(DumpWriter* writer) {
if (writer->is_open()) {
julong dump_end = writer->bytes_written() + writer->bytes_unwritten();
julong dump_len = writer->current_record_length();
if (dump_len > max_juint) {
warning("record is too large");
}
assert(writer->dump_start() >= 0, "no dump start recorded");
writer->seek_to_offset(writer->dump_start());
writer->write_u4((u4)dump_len);
writer->adjust_bytes_written(-((jlong) sizeof(u4)));
writer->seek_to_offset(dump_end);
writer->set_dump_start((jlong)-1);
}
}
void VM_HeapDumper::check_segment_length() {
if (writer()->is_open()) {
julong dump_len = writer()->current_record_length();
if (dump_len > 2UL*G) {
DumperSupport::write_current_dump_record_length(writer());
DumperSupport::write_dump_header(writer());
}
}
}
void DumperSupport::end_of_dump(DumpWriter* writer) {
if (writer->is_open()) {
write_current_dump_record_length(writer);
writer->write_u1(HPROF_HEAP_DUMP_END);
writer->write_u4(0);
writer->write_u4(0);
}
}
void HeapObjectDumper::mark_end_of_record() {
dumper()->check_segment_length();
}
void VM_HeapDumper::do_load_class(Klass* k) {
static u4 class_serial_num = 0;
u4 remaining = 2*oopSize + 2*sizeof(u4);
do {
DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining);
writer()->write_u4(++class_serial_num);
Klass* klass = k;
writer()->write_classID(klass);
dumper()->add_class_serial_number(klass, class_serial_num);
writer()->write_u4(STACK_TRACE_ID);
Symbol* name = klass->name();
writer()->write_symbolID(name);
k = klass->array_klass_or_null();
} while (k != NULL);
}
void VM_HeapDumper::do_class_dump(Klass* k) {
if (k->oop_is_instance()) {
DumperSupport::dump_class_and_array_classes(writer(), k);
}
}
void VM_HeapDumper::do_basic_type_array_class_dump(Klass* k) {
DumperSupport::dump_basic_type_array_class(writer(), k);
}
int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) {
JNILocalsDumper blk(writer(), thread_serial_num);
oop threadObj = java_thread->threadObj();
assert(threadObj != NULL, "sanity check");
int stack_depth = 0;
if (java_thread->has_last_Java_frame()) {
Thread* current_thread = Thread::current();
ResourceMark rm(current_thread);
HandleMark hm(current_thread);
RegisterMap reg_map(java_thread);
frame f = java_thread->last_frame();
vframe* vf = vframe::new_vframe(&f, ®_map, java_thread);
frame* last_entry_frame = NULL;
int extra_frames = 0;
if (java_thread == _oome_thread && _oome_constructor != NULL) {
extra_frames++;
}
while (vf != NULL) {
blk.set_frame_number(stack_depth);
if (vf->is_java_frame()) {
javaVFrame *jvf = javaVFrame::cast(vf);
if (!(jvf->method()->is_native())) {
StackValueCollection* locals = jvf->locals();
for (int slot=0; slot<locals->size(); slot++) {
if (locals->at(slot)->type() == T_OBJECT) {
oop o = locals->obj_at(slot)();
if (o != NULL) {
writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME);
writer()->write_objectID(o);
writer()->write_u4(thread_serial_num);
writer()->write_u4((u4) (stack_depth + extra_frames));
}
}
}
} else {
if (stack_depth == 0) {
java_thread->active_handles()->oops_do(&blk);
} else {
if (last_entry_frame != NULL) {
assert(last_entry_frame->is_entry_frame(), "checking");
last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(&blk);
}
}
}
stack_depth++;
last_entry_frame = NULL;
} else {
frame* fr = vf->frame_pointer();
assert(fr != NULL, "sanity check");
if (fr->is_entry_frame()) {
last_entry_frame = fr;
}
}
vf = vf->sender();
}
} else {
java_thread->active_handles()->oops_do(&blk);
}
return stack_depth;
}
void VM_HeapDumper::do_threads() {
for (int i=0; i < _num_threads; i++) {
JavaThread* thread = _stack_traces[i]->thread();
oop threadObj = thread->threadObj();
u4 thread_serial_num = i+1;
u4 stack_serial_num = thread_serial_num + STACK_TRACE_ID;
writer()->write_u1(HPROF_GC_ROOT_THREAD_OBJ);
writer()->write_objectID(threadObj);
writer()->write_u4(thread_serial_num); // thread number
writer()->write_u4(stack_serial_num); // stack trace serial number
int num_frames = do_thread(thread, thread_serial_num);
assert(num_frames == _stack_traces[i]->get_stack_depth(),
"total number of Java frames not matched");
}
}
void VM_HeapDumper::doit() {
HandleMark hm;
CollectedHeap* ch = Universe::heap();
ch->ensure_parsability(false); // must happen, even if collection does
if (_gc_before_heap_dump) {
if (GC_locker::is_active()) {
warning("GC locker is held; pre-heapdump GC was skipped");
} else {
ch->collect_as_vm_thread(GCCause::_heap_dump);
}
}
set_global_dumper();
set_global_writer();
size_t used = ch->used();
const char* header = "JAVA PROFILE 1.0.2";
writer()->write_raw((void*)header, (int)strlen(header));
writer()->write_u1(0); // terminator
writer()->write_u4(oopSize);
writer()->write_u8(os::javaTimeMillis());
SymbolTableDumper sym_dumper(writer());
SymbolTable::symbols_do(&sym_dumper);
ClassLoaderDataGraph::classes_do(&do_load_class);
Universe::basic_type_classes_do(&do_load_class);
dump_stack_traces();
DumperSupport::write_dump_header(writer());
ClassLoaderDataGraph::classes_do(&do_class_dump);
Universe::basic_type_classes_do(&do_basic_type_array_class_dump);
check_segment_length();
HeapObjectDumper obj_dumper(this, writer());
Universe::heap()->safe_object_iterate(&obj_dumper);
do_threads();
check_segment_length();
MonitorUsedDumper mon_dumper(writer());
ObjectSynchronizer::oops_do(&mon_dumper);
check_segment_length();
JNIGlobalsDumper jni_dumper(writer());
JNIHandles::oops_do(&jni_dumper);
Universe::oops_do(&jni_dumper); // technically not jni roots, but global roots
check_segment_length();
StickyClassDumper class_dumper(writer());
SystemDictionary::always_strong_classes_do(&class_dumper);
DumperSupport::end_of_dump(writer());
clear_global_dumper();
clear_global_writer();
}
void VM_HeapDumper::dump_stack_traces() {
DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4));
writer()->write_u4((u4) STACK_TRACE_ID);
writer()->write_u4(0); // thread number
writer()->write_u4(0); // frame count
_stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads(), mtInternal);
int frame_serial_num = 0;
for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
oop threadObj = thread->threadObj();
if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false);
stack_trace->dump_stack_at_safepoint(-1);
_stack_traces[_num_threads++] = stack_trace;
int depth = stack_trace->get_stack_depth();
int thread_frame_start = frame_serial_num;
int extra_frames = 0;
if (thread == _oome_thread && _oome_constructor != NULL) {
int oome_serial_num = _klass_map->find(_oome_constructor->method_holder());
assert(oome_serial_num > 0, "OutOfMemoryError class not found");
DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num,
_oome_constructor, 0);
extra_frames++;
}
for (int j=0; j < depth; j++) {
StackFrameInfo* frame = stack_trace->stack_frame_at(j);
Method* m = frame->method();
int class_serial_num = _klass_map->find(m->method_holder());
assert(class_serial_num > 0, "class not found");
DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci());
}
depth += extra_frames;
DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize);
int stack_serial_num = _num_threads + STACK_TRACE_ID;
writer()->write_u4(stack_serial_num); // stack trace serial number
writer()->write_u4((u4) _num_threads); // thread serial number
writer()->write_u4(depth); // frame count
for (int j=1; j <= depth; j++) {
writer()->write_id(thread_frame_start + j);
}
}
}
}
PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL
int HeapDumper::dump(const char* path) {
assert(path != NULL && strlen(path) > 0, "path missing");
if (print_to_tty()) {
tty->print_cr("Dumping heap to %s ...", path);
timer()->start();
}
DumpWriter writer(path);
if (!writer.is_open()) {
set_error(writer.error());
if (print_to_tty()) {
tty->print_cr("Unable to create %s: %s", path,
(error() != NULL) ? error() : "reason unknown");
}
return -1;
}
VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome);
if (Thread::current()->is_VM_thread()) {
assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint");
dumper.doit();
} else {
VMThread::execute(&dumper);
}
writer.close();
set_error(writer.error());
if (print_to_tty()) {
timer()->stop();
if (error() == NULL) {
tty->print_cr("Heap dump file created [" JULONG_FORMAT " bytes in %3.3f secs]",
writer.bytes_written(), timer()->seconds());
} else {
tty->print_cr("Dump file is incomplete: %s", writer.error());
}
}
return (writer.error() == NULL) ? 0 : -1;
}
HeapDumper::~HeapDumper() {
if (timer()->is_active()) {
timer()->stop();
}
set_error(NULL);
}
char* HeapDumper::error_as_C_string() const {
if (error() != NULL) {
char* str = NEW_RESOURCE_ARRAY(char, strlen(error())+1);
strcpy(str, error());
return str;
} else {
return NULL;
}
}
void HeapDumper::set_error(char* error) {
if (_error != NULL) {
os::free(_error);
}
if (error == NULL) {
_error = NULL;
} else {
_error = os::strdup(error);
assert(_error != NULL, "allocation failure");
}
}
void HeapDumper::dump_heap_from_oome() {
HeapDumper::dump_heap(true);
}
void HeapDumper::dump_heap() {
HeapDumper::dump_heap(false);
}
void HeapDumper::dump_heap(bool oome) {
static char base_path[JVM_MAXPATHLEN] = {'\0'};
static uint dump_file_seq = 0;
char* my_path;
const int max_digit_chars = 20;
const char* dump_file_name = "java_pid";
const char* dump_file_ext = ".hprof";
if (dump_file_seq == 0) { // first time in, we initialize base_path
const size_t total_length =
(HeapDumpPath == NULL ? 0 : strlen(HeapDumpPath)) +
strlen(os::file_separator()) + max_digit_chars +
strlen(dump_file_name) + strlen(dump_file_ext) + 1;
if (total_length > sizeof(base_path)) {
warning("Cannot create heap dump file. HeapDumpPath is too long.");
return;
}
bool use_default_filename = true;
if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
} else {
strncpy(base_path, HeapDumpPath, sizeof(base_path));
DIR* dir = os::opendir(base_path);
if (dir == NULL) {
use_default_filename = false;
} else {
os::closedir(dir);
size_t fs_len = strlen(os::file_separator());
if (strlen(base_path) >= fs_len) {
char* end = base_path;
end += (strlen(base_path) - fs_len);
if (strcmp(end, os::file_separator()) != 0) {
strcat(base_path, os::file_separator());
}
}
}
}
if (use_default_filename) {
const size_t dlen = strlen(base_path); // if heap dump dir specified
jio_snprintf(&base_path[dlen], sizeof(base_path)-dlen, "%s%d%s",
dump_file_name, os::current_process_id(), dump_file_ext);
}
const size_t len = strlen(base_path) + 1;
my_path = (char*)os::malloc(len, mtInternal);
if (my_path == NULL) {
warning("Cannot create heap dump file. Out of system memory.");
return;
}
strncpy(my_path, base_path, len);
} else {
const size_t len = strlen(base_path) + max_digit_chars + 2; // for '.' and \0
my_path = (char*)os::malloc(len, mtInternal);
if (my_path == NULL) {
warning("Cannot create heap dump file. Out of system memory.");
return;
}
jio_snprintf(my_path, len, "%s.%d", base_path, dump_file_seq);
}
dump_file_seq++; // increment seq number for next time we dump
HeapDumper dumper(false /* no GC before heap dump */,
true /* send to tty */,
oome /* pass along out-of-memory-error flag */);
dumper.dump(my_path);
os::free(my_path);
}
C:\hotspot-69087d08d473\src\share\vm/services/heapDumper.hpp
#ifndef SHARE_VM_SERVICES_HEAPDUMPER_HPP
#define SHARE_VM_SERVICES_HEAPDUMPER_HPP
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
#include "runtime/os.hpp"
class HeapDumper : public StackObj {
private:
char* _error;
bool _print_to_tty;
bool _gc_before_heap_dump;
bool _oome;
elapsedTimer _t;
HeapDumper(bool gc_before_heap_dump, bool print_to_tty, bool oome) :
_gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(print_to_tty), _oome(oome) { }
char* error() const { return _error; }
void set_error(char* error);
bool print_to_tty() const { return _print_to_tty; }
elapsedTimer* timer() { return &_t; }
static void dump_heap(bool oome);
public:
HeapDumper(bool gc_before_heap_dump) :
_gc_before_heap_dump(gc_before_heap_dump), _error(NULL), _print_to_tty(false), _oome(false) { }
~HeapDumper();
int dump(const char* path);
char* error_as_C_string() const;
static void dump_heap() NOT_SERVICES_RETURN;
static void dump_heap_from_oome() NOT_SERVICES_RETURN;
};
#endif // SHARE_VM_SERVICES_HEAPDUMPER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/jmm.h
#ifndef _JAVA_JMM_H_
#define _JAVA_JMM_H_
#include "jni.h"
#ifdef __cplusplus
extern "C" {
#endif
enum {
JMM_VERSION_1 = 0x20010000,
JMM_VERSION_1_0 = 0x20010000,
JMM_VERSION_1_1 = 0x20010100, // JDK 6
JMM_VERSION_1_2 = 0x20010200, // JDK 7
JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
JMM_VERSION_1_2_2 = 0x20010202,
JMM_VERSION = 0x20010203
};
typedef struct {
unsigned int isLowMemoryDetectionSupported : 1;
unsigned int isCompilationTimeMonitoringSupported : 1;
unsigned int isThreadContentionMonitoringSupported : 1;
unsigned int isCurrentThreadCpuTimeSupported : 1;
unsigned int isOtherThreadCpuTimeSupported : 1;
unsigned int isBootClassPathSupported : 1;
unsigned int isObjectMonitorUsageSupported : 1;
unsigned int isSynchronizerUsageSupported : 1;
unsigned int isThreadAllocatedMemorySupported : 1;
unsigned int isRemoteDiagnosticCommandsSupported : 1;
unsigned int : 22;
} jmmOptionalSupport;
typedef enum {
JMM_CLASS_LOADED_COUNT = 1, /* Total number of loaded classes */
JMM_CLASS_UNLOADED_COUNT = 2, /* Total number of unloaded classes */
JMM_THREAD_TOTAL_COUNT = 3, /* Total number of threads that have been started */
JMM_THREAD_LIVE_COUNT = 4, /* Current number of live threads */
JMM_THREAD_PEAK_COUNT = 5, /* Peak number of live threads */
JMM_THREAD_DAEMON_COUNT = 6, /* Current number of daemon threads */
JMM_JVM_INIT_DONE_TIME_MS = 7, /* Time when the JVM finished initialization */
JMM_COMPILE_TOTAL_TIME_MS = 8, /* Total accumulated time spent in compilation */
JMM_GC_TIME_MS = 9, /* Total accumulated time spent in collection */
JMM_GC_COUNT = 10, /* Total number of collections */
JMM_JVM_UPTIME_MS = 11, /* The JVM uptime in milliseconds */
JMM_INTERNAL_ATTRIBUTE_INDEX = 100,
JMM_CLASS_LOADED_BYTES = 101, /* Number of bytes loaded instance classes */
JMM_CLASS_UNLOADED_BYTES = 102, /* Number of bytes unloaded instance classes */
JMM_TOTAL_CLASSLOAD_TIME_MS = 103, /* Accumulated VM class loader time (TraceClassLoadingTime) */
JMM_VM_GLOBAL_COUNT = 104, /* Number of VM internal flags */
JMM_SAFEPOINT_COUNT = 105, /* Total number of safepoints */
JMM_TOTAL_SAFEPOINTSYNC_TIME_MS = 106, /* Accumulated time spent getting to safepoints */
JMM_TOTAL_STOPPED_TIME_MS = 107, /* Accumulated time spent at safepoints */
JMM_TOTAL_APP_TIME_MS = 108, /* Accumulated time spent in Java application */
JMM_VM_THREAD_COUNT = 109, /* Current number of VM internal threads */
JMM_CLASS_INIT_TOTAL_COUNT = 110, /* Number of classes for which initializers were run */
JMM_CLASS_INIT_TOTAL_TIME_MS = 111, /* Accumulated time spent in class initializers */
JMM_METHOD_DATA_SIZE_BYTES = 112, /* Size of method data in memory */
JMM_CLASS_VERIFY_TOTAL_TIME_MS = 113, /* Accumulated time spent in class verifier */
JMM_SHARED_CLASS_LOADED_COUNT = 114, /* Number of shared classes loaded */
JMM_SHARED_CLASS_UNLOADED_COUNT = 115, /* Number of shared classes unloaded */
JMM_SHARED_CLASS_LOADED_BYTES = 116, /* Number of bytes loaded shared classes */
JMM_SHARED_CLASS_UNLOADED_BYTES = 117, /* Number of bytes unloaded shared classes */
JMM_OS_ATTRIBUTE_INDEX = 200,
JMM_OS_PROCESS_ID = 201, /* Process id of the JVM */
JMM_OS_MEM_TOTAL_PHYSICAL_BYTES = 202, /* Physical memory size */
JMM_GC_EXT_ATTRIBUTE_INFO_SIZE = 401 /* the size of the GC specific attributes for a given GC memory manager */
} jmmLongAttribute;
typedef enum {
JMM_VERBOSE_GC = 21,
JMM_VERBOSE_CLASS = 22,
JMM_THREAD_CONTENTION_MONITORING = 23,
JMM_THREAD_CPU_TIME = 24,
JMM_THREAD_ALLOCATED_MEMORY = 25
} jmmBoolAttribute;
enum {
JMM_THREAD_STATE_FLAG_SUSPENDED = 0x00100000,
JMM_THREAD_STATE_FLAG_NATIVE = 0x00400000
};
#define JMM_THREAD_STATE_FLAG_MASK 0xFFF00000
typedef enum {
JMM_STAT_PEAK_THREAD_COUNT = 801,
JMM_STAT_THREAD_CONTENTION_COUNT = 802,
JMM_STAT_THREAD_CONTENTION_TIME = 803,
JMM_STAT_THREAD_CONTENTION_STAT = 804,
JMM_STAT_PEAK_POOL_USAGE = 805,
JMM_STAT_GC_STAT = 806
} jmmStatisticType;
typedef enum {
JMM_USAGE_THRESHOLD_HIGH = 901,
JMM_USAGE_THRESHOLD_LOW = 902,
JMM_COLLECTION_USAGE_THRESHOLD_HIGH = 903,
JMM_COLLECTION_USAGE_THRESHOLD_LOW = 904
} jmmThresholdType;
typedef enum {
JMM_VMGLOBAL_TYPE_UNKNOWN = 0,
JMM_VMGLOBAL_TYPE_JBOOLEAN = 1,
JMM_VMGLOBAL_TYPE_JSTRING = 2,
JMM_VMGLOBAL_TYPE_JLONG = 3,
JMM_VMGLOBAL_TYPE_JDOUBLE = 4
} jmmVMGlobalType;
typedef enum {
JMM_VMGLOBAL_ORIGIN_DEFAULT = 1, /* Default value */
JMM_VMGLOBAL_ORIGIN_COMMAND_LINE = 2, /* Set at command line (or JNI invocation) */
JMM_VMGLOBAL_ORIGIN_MANAGEMENT = 3, /* Set via management interface */
JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR = 4, /* Set via environment variables */
JMM_VMGLOBAL_ORIGIN_CONFIG_FILE = 5, /* Set via config file (such as .hotspotrc) */
JMM_VMGLOBAL_ORIGIN_ERGONOMIC = 6, /* Set via ergonomic */
JMM_VMGLOBAL_ORIGIN_OTHER = 99 /* Set via some other mechanism */
} jmmVMGlobalOrigin;
typedef struct {
jstring name;
jvalue value;
jmmVMGlobalType type; /* Data type */
jmmVMGlobalOrigin origin; /* Default or non-default value */
unsigned int writeable : 1; /* dynamically writeable */
unsigned int external : 1; /* external supported interface */
unsigned int reserved : 30;
void *reserved1;
void *reserved2;
} jmmVMGlobal;
typedef struct {
const char* name;
char type;
const char* description;
} jmmExtAttributeInfo;
typedef struct {
jlong gc_index; /* Index of the collections */
jlong start_time; /* Start time of the GC */
jlong end_time; /* End time of the GC */
jobjectArray usage_before_gc; /* Memory usage array before GC */
jobjectArray usage_after_gc; /* Memory usage array after GC */
jint gc_ext_attribute_values_size; /* set by the caller of GetGCStat */
jvalue* gc_ext_attribute_values; /* Array of jvalue for GC extension attributes */
jint num_gc_ext_attributes; /* number of GC extension attribute values s are filled */
} jmmGCStat;
typedef struct {
const char* name; /* Name of the diagnostic command */
const char* description; /* Short description */
const char* impact; /* Impact on the JVM */
const char* permission_class; /* Class name of the required permission if any */
const char* permission_name; /* Permission name of the required permission if any */
const char* permission_action; /* Action name of the required permission if any*/
int num_arguments; /* Number of supported options or arguments */
jboolean enabled; /* True if the diagnostic command can be invoked, false otherwise */
} dcmdInfo;
typedef struct {
const char* name; /* Option/Argument name*/
const char* description; /* Short description */
const char* type; /* Type: STRING, BOOLEAN, etc. */
const char* default_string; /* Default value in a parsable string */
jboolean mandatory; /* True if the option/argument is mandatory */
jboolean option; /* True if it is an option, false if it is an argument */
jboolean multiple; /* True if the option can be specified several time */
int position; /* Expected position for this argument (this field is */
} dcmdArgInfo;
typedef struct jmmInterface_1_ {
void* reserved1;
jlong (JNICALL *GetOneThreadAllocatedMemory)
(JNIEnv *env,
jlong thread_id);
jint (JNICALL *GetVersion) (JNIEnv *env);
jint (JNICALL *GetOptionalSupport) (JNIEnv *env,
jmmOptionalSupport* support_ptr);
jobject (JNICALL *GetInputArguments) (JNIEnv *env);
jint (JNICALL *GetThreadInfo) (JNIEnv *env,
jlongArray ids,
jint maxDepth,
jobjectArray infoArray);
jobjectArray (JNICALL *GetInputArgumentArray) (JNIEnv *env);
jobjectArray (JNICALL *GetMemoryPools) (JNIEnv* env, jobject mgr);
jobjectArray (JNICALL *GetMemoryManagers) (JNIEnv* env, jobject pool);
jobject (JNICALL *GetMemoryPoolUsage) (JNIEnv* env, jobject pool);
jobject (JNICALL *GetPeakMemoryPoolUsage) (JNIEnv* env, jobject pool);
void (JNICALL *GetThreadAllocatedMemory)
(JNIEnv *env,
jlongArray ids,
jlongArray sizeArray);
jobject (JNICALL *GetMemoryUsage) (JNIEnv* env, jboolean heap);
jlong (JNICALL *GetLongAttribute) (JNIEnv *env, jobject obj, jmmLongAttribute att);
jboolean (JNICALL *GetBoolAttribute) (JNIEnv *env, jmmBoolAttribute att);
jboolean (JNICALL *SetBoolAttribute) (JNIEnv *env, jmmBoolAttribute att, jboolean flag);
jint (JNICALL *GetLongAttributes) (JNIEnv *env,
jobject obj,
jmmLongAttribute* atts,
jint count,
jlong* result);
jobjectArray (JNICALL *FindCircularBlockedThreads) (JNIEnv *env);
jlong (JNICALL *GetThreadCpuTime) (JNIEnv *env, jlong thread_id);
jobjectArray (JNICALL *GetVMGlobalNames) (JNIEnv *env);
jint (JNICALL *GetVMGlobals) (JNIEnv *env,
jobjectArray names,
jmmVMGlobal *globals,
jint count);
jint (JNICALL *GetInternalThreadTimes) (JNIEnv *env,
jobjectArray names,
jlongArray times);
jboolean (JNICALL *ResetStatistic) (JNIEnv *env,
jvalue obj,
jmmStatisticType type);
void (JNICALL *SetPoolSensor) (JNIEnv *env,
jobject pool,
jmmThresholdType type,
jobject sensor);
jlong (JNICALL *SetPoolThreshold) (JNIEnv *env,
jobject pool,
jmmThresholdType type,
jlong threshold);
jobject (JNICALL *GetPoolCollectionUsage) (JNIEnv* env, jobject pool);
jint (JNICALL *GetGCExtAttributeInfo) (JNIEnv *env,
jobject mgr,
jmmExtAttributeInfo *ext_info,
jint count);
void (JNICALL *GetLastGCStat) (JNIEnv *env,
jobject mgr,
jmmGCStat *gc_stat);
jlong (JNICALL *GetThreadCpuTimeWithKind)
(JNIEnv *env,
jlong thread_id,
jboolean user_sys_cpu_time);
void (JNICALL *GetThreadCpuTimesWithKind)
(JNIEnv *env,
jlongArray ids,
jlongArray timeArray,
jboolean user_sys_cpu_time);
jint (JNICALL *DumpHeap0) (JNIEnv *env,
jstring outputfile,
jboolean live);
jobjectArray (JNICALL *FindDeadlocks) (JNIEnv *env,
jboolean object_monitors_only);
void (JNICALL *SetVMGlobal) (JNIEnv *env,
jstring flag_name,
jvalue new_value);
jobjectArray (JNICALL *DumpThreadsMaxDepth) (JNIEnv *env,
jlongArray ids,
jboolean lockedMonitors,
jboolean lockedSynchronizers,
jint maxDepth);
jobjectArray (JNICALL *DumpThreads) (JNIEnv *env,
jlongArray ids,
jboolean lockedMonitors,
jboolean lockedSynchronizers);
void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
jobject mgr,
jboolean enabled);
jobjectArray (JNICALL *GetDiagnosticCommands) (JNIEnv *env);
void (JNICALL *GetDiagnosticCommandInfo)
(JNIEnv *env,
jobjectArray cmds,
dcmdInfo *infoArray);
void (JNICALL *GetDiagnosticCommandArgumentsInfo)
(JNIEnv *env,
jstring commandName,
dcmdArgInfo *infoArray);
jstring (JNICALL *ExecuteDiagnosticCommand)
(JNIEnv *env,
jstring command);
void (JNICALL *SetDiagnosticFrameworkNotificationEnabled)
(JNIEnv *env,
jboolean enabled);
} JmmInterface;
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* !_JAVA_JMM_H_ */
C:\hotspot-69087d08d473\src\share\vm/services/lowMemoryDetector.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "services/lowMemoryDetector.hpp"
#include "services/management.hpp"
volatile bool LowMemoryDetector::_enabled_for_collected_pools = false;
volatile jint LowMemoryDetector::_disabled_count = 0;
bool LowMemoryDetector::has_pending_requests() {
assert(Service_lock->owned_by_self(), "Must own Service_lock");
bool has_requests = false;
int num_memory_pools = MemoryService::num_memory_pools();
for (int i = 0; i < num_memory_pools; i++) {
MemoryPool* pool = MemoryService::get_memory_pool(i);
SensorInfo* sensor = pool->usage_sensor();
if (sensor != NULL) {
has_requests = has_requests || sensor->has_pending_requests();
}
SensorInfo* gc_sensor = pool->gc_usage_sensor();
if (gc_sensor != NULL) {
has_requests = has_requests || gc_sensor->has_pending_requests();
}
}
return has_requests;
}
void LowMemoryDetector::process_sensor_changes(TRAPS) {
ResourceMark rm(THREAD);
HandleMark hm(THREAD);
int num_memory_pools = MemoryService::num_memory_pools();
for (int i = 0; i < num_memory_pools; i++) {
MemoryPool* pool = MemoryService::get_memory_pool(i);
SensorInfo* sensor = pool->usage_sensor();
SensorInfo* gc_sensor = pool->gc_usage_sensor();
if (sensor != NULL && sensor->has_pending_requests()) {
sensor->process_pending_requests(CHECK);
}
if (gc_sensor != NULL && gc_sensor->has_pending_requests()) {
gc_sensor->process_pending_requests(CHECK);
}
}
}
void LowMemoryDetector::detect_low_memory() {
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
bool has_pending_requests = false;
int num_memory_pools = MemoryService::num_memory_pools();
for (int i = 0; i < num_memory_pools; i++) {
MemoryPool* pool = MemoryService::get_memory_pool(i);
SensorInfo* sensor = pool->usage_sensor();
if (sensor != NULL &&
pool->usage_threshold()->is_high_threshold_supported() &&
pool->usage_threshold()->high_threshold() != 0) {
MemoryUsage usage = pool->get_memory_usage();
sensor->set_gauge_sensor_level(usage,
pool->usage_threshold());
has_pending_requests = has_pending_requests || sensor->has_pending_requests();
}
}
if (has_pending_requests) {
Service_lock->notify_all();
}
}
void LowMemoryDetector::detect_low_memory(MemoryPool* pool) {
SensorInfo* sensor = pool->usage_sensor();
if (sensor == NULL ||
!pool->usage_threshold()->is_high_threshold_supported() ||
pool->usage_threshold()->high_threshold() == 0) {
return;
}
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
MemoryUsage usage = pool->get_memory_usage();
sensor->set_gauge_sensor_level(usage,
pool->usage_threshold());
if (sensor->has_pending_requests()) {
Service_lock->notify_all();
}
}
}
void LowMemoryDetector::detect_after_gc_memory(MemoryPool* pool) {
SensorInfo* sensor = pool->gc_usage_sensor();
if (sensor == NULL ||
!pool->gc_usage_threshold()->is_high_threshold_supported() ||
pool->gc_usage_threshold()->high_threshold() == 0) {
return;
}
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
MemoryUsage usage = pool->get_last_collection_usage();
sensor->set_counter_sensor_level(usage, pool->gc_usage_threshold());
if (sensor->has_pending_requests()) {
Service_lock->notify_all();
}
}
}
void LowMemoryDetector::recompute_enabled_for_collected_pools() {
bool enabled = false;
int num_memory_pools = MemoryService::num_memory_pools();
for (int i=0; i<num_memory_pools; i++) {
MemoryPool* pool = MemoryService::get_memory_pool(i);
if (pool->is_collected_pool() && is_enabled(pool)) {
enabled = true;
break;
}
}
_enabled_for_collected_pools = enabled;
}
SensorInfo::SensorInfo() {
_sensor_obj = NULL;
_sensor_on = false;
_sensor_count = 0;
_pending_trigger_count = 0;
_pending_clear_count = 0;
}
void SensorInfo::set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold) {
assert(high_low_threshold->is_high_threshold_supported(), "just checking");
bool is_over_high = high_low_threshold->is_high_threshold_crossed(usage);
bool is_below_low = high_low_threshold->is_low_threshold_crossed(usage);
assert(!(is_over_high && is_below_low), "Can't be both true");
if (is_over_high &&
((!_sensor_on && _pending_trigger_count == 0) ||
_pending_clear_count > 0)) {
_pending_trigger_count++;
_usage = usage;
if (_pending_clear_count > 0) {
_pending_clear_count = 0;
}
} else if (is_below_low &&
((_sensor_on && _pending_clear_count == 0) ||
(_pending_trigger_count > 0 && _pending_clear_count == 0))) {
_pending_clear_count++;
}
}
void SensorInfo::set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold) {
assert(counter_threshold->is_high_threshold_supported(), "just checking");
bool is_over_high = counter_threshold->is_high_threshold_crossed(usage);
bool is_below_low = counter_threshold->is_low_threshold_crossed(usage);
assert(!(is_over_high && is_below_low), "Can't be both true");
if (is_over_high) {
_pending_trigger_count++;
_usage = usage;
_pending_clear_count = 0;
} else if (is_below_low && (_sensor_on || _pending_trigger_count > 0)) {
_pending_clear_count++;
}
}
void SensorInfo::oops_do(OopClosure* f) {
f->do_oop((oop*) &_sensor_obj);
}
void SensorInfo::process_pending_requests(TRAPS) {
if (!has_pending_requests()) {
return;
}
int pending_count = pending_trigger_count();
if (pending_clear_count() > 0) {
clear(pending_count, CHECK);
} else {
trigger(pending_count, CHECK);
}
}
void SensorInfo::trigger(int count, TRAPS) {
assert(count <= _pending_trigger_count, "just checking");
if (_sensor_obj != NULL) {
Klass* k = Management::sun_management_Sensor_klass(CHECK);
instanceKlassHandle sensorKlass (THREAD, k);
Handle sensor_h(THREAD, _sensor_obj);
Symbol* trigger_method_signature;
JavaValue result(T_VOID);
JavaCallArguments args(sensor_h);
args.push_int((int) count);
Handle usage_h = MemoryService::create_MemoryUsage_obj(_usage, THREAD);
if (HAS_PENDING_EXCEPTION) {
assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOME here");
CLEAR_PENDING_EXCEPTION;
trigger_method_signature = vmSymbols::int_void_signature();
} else {
trigger_method_signature = vmSymbols::trigger_method_signature();
args.push_oop(usage_h);
}
JavaCalls::call_virtual(&result,
sensorKlass,
vmSymbols::trigger_name(),
trigger_method_signature,
&args,
THREAD);
if (HAS_PENDING_EXCEPTION) {
assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOME here");
CLEAR_PENDING_EXCEPTION;
}
}
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
_sensor_on = true;
_sensor_count += count;
_pending_trigger_count = _pending_trigger_count - count;
}
}
void SensorInfo::clear(int count, TRAPS) {
if (_sensor_obj != NULL) {
Klass* k = Management::sun_management_Sensor_klass(CHECK);
instanceKlassHandle sensorKlass (THREAD, k);
Handle sensor(THREAD, _sensor_obj);
JavaValue result(T_VOID);
JavaCallArguments args(sensor);
args.push_int((int) count);
JavaCalls::call_virtual(&result,
sensorKlass,
vmSymbols::clear_name(),
vmSymbols::int_void_signature(),
&args,
CHECK);
}
{
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
_sensor_on = false;
_pending_clear_count = 0;
_pending_trigger_count = _pending_trigger_count - count;
}
}
#ifndef PRODUCT
void SensorInfo::print() {
tty->print_cr("%s count = " SIZE_FORMAT " pending_triggers = %d pending_clears = %d",
(_sensor_on ? "on" : "off"),
_sensor_count, _pending_trigger_count, _pending_clear_count);
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/services/lowMemoryDetector.hpp
#ifndef SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP
#define SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP
#include "memory/allocation.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryService.hpp"
class OopClosure;
class MemoryPool;
class ThresholdSupport : public CHeapObj<mtInternal> {
private:
bool _support_high_threshold;
bool _support_low_threshold;
size_t _high_threshold;
size_t _low_threshold;
public:
ThresholdSupport(bool support_high, bool support_low) {
_support_high_threshold = support_high;
_support_low_threshold = support_low;
_high_threshold = 0;
_low_threshold= 0;
}
size_t high_threshold() const { return _high_threshold; }
size_t low_threshold() const { return _low_threshold; }
bool is_high_threshold_supported() { return _support_high_threshold; }
bool is_low_threshold_supported() { return _support_low_threshold; }
bool is_high_threshold_crossed(MemoryUsage usage) {
if (_support_high_threshold && _high_threshold > 0) {
return (usage.used() >= _high_threshold);
}
return false;
}
bool is_low_threshold_crossed(MemoryUsage usage) {
if (_support_low_threshold && _low_threshold > 0) {
return (usage.used() < _low_threshold);
}
return false;
}
size_t set_high_threshold(size_t new_threshold) {
assert(_support_high_threshold, "can only be set if supported");
assert(new_threshold >= _low_threshold, "new_threshold must be >= _low_threshold");
size_t prev = _high_threshold;
_high_threshold = new_threshold;
return prev;
}
size_t set_low_threshold(size_t new_threshold) {
assert(_support_low_threshold, "can only be set if supported");
assert(new_threshold <= _high_threshold, "new_threshold must be <= _high_threshold");
size_t prev = _low_threshold;
_low_threshold = new_threshold;
return prev;
}
};
class SensorInfo : public CHeapObj<mtInternal> {
private:
instanceOop _sensor_obj;
bool _sensor_on;
size_t _sensor_count;
int _pending_trigger_count;
int _pending_clear_count;
MemoryUsage _usage;
void clear(int count, TRAPS);
void trigger(int count, TRAPS);
public:
SensorInfo();
void set_sensor(instanceOop sensor) {
assert(_sensor_obj == NULL, "Should be set only once");
_sensor_obj = sensor;
}
bool has_pending_requests() {
return (_pending_trigger_count > 0 || _pending_clear_count > 0);
}
int pending_trigger_count() { return _pending_trigger_count; }
int pending_clear_count() { return _pending_clear_count; }
void set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold);
void set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold);
void process_pending_requests(TRAPS);
void oops_do(OopClosure* f);
#ifndef PRODUCT
void print();
#endif // PRODUCT
};
class LowMemoryDetector : public AllStatic {
friend class LowMemoryDetectorDisabler;
friend class ServiceThread;
private:
static volatile bool _enabled_for_collected_pools;
static volatile jint _disabled_count;
static void check_memory_usage();
static bool has_pending_requests();
static bool temporary_disabled() { return _disabled_count > 0; }
static void disable() { Atomic::inc(&_disabled_count); }
static void enable() { Atomic::dec(&_disabled_count); }
static void process_sensor_changes(TRAPS);
public:
static void detect_low_memory();
static void detect_low_memory(MemoryPool* pool);
static void detect_after_gc_memory(MemoryPool* pool);
static bool is_enabled(MemoryPool* pool) {
if (pool->usage_sensor() == NULL) {
return false;
} else {
ThresholdSupport* threshold_support = pool->usage_threshold();
return (threshold_support->is_high_threshold_supported() ?
(threshold_support->high_threshold() > 0) : false);
}
}
static inline bool is_enabled_for_collected_pools() {
return !temporary_disabled() && _enabled_for_collected_pools;
}
static void recompute_enabled_for_collected_pools();
static inline void detect_low_memory_for_collected_pools() {
if (!is_enabled_for_collected_pools()) {
return;
}
int num_memory_pools = MemoryService::num_memory_pools();
for (int i=0; i<num_memory_pools; i++) {
MemoryPool* pool = MemoryService::get_memory_pool(i);
if (pool->is_collected_pool() && is_enabled(pool)) {
size_t used = pool->used_in_bytes();
size_t high = pool->usage_threshold()->high_threshold();
if (used > high) {
detect_low_memory(pool);
}
}
}
}
};
class LowMemoryDetectorDisabler: public StackObj {
public:
LowMemoryDetectorDisabler()
{
LowMemoryDetector::disable();
}
~LowMemoryDetectorDisabler()
{
assert(LowMemoryDetector::temporary_disabled(), "should be disabled!");
LowMemoryDetector::enable();
}
};
#endif // SHARE_VM_SERVICES_LOWMEMORYDETECTOR_HPP
C:\hotspot-69087d08d473\src\share\vm/services/mallocSiteTable.cpp
#include "precompiled.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/atomic.hpp"
#include "services/mallocSiteTable.hpp"
size_t MallocSiteTable::_hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)];
size_t MallocSiteTable::_hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)];
MallocSiteHashtableEntry* MallocSiteTable::_table[MallocSiteTable::table_size];
volatile int MallocSiteTable::_access_count = 0;
NOT_PRODUCT(int MallocSiteTable::_peak_count = 0;)
bool MallocSiteTable::initialize() {
assert(sizeof(_hash_entry_allocation_stack) >= sizeof(NativeCallStack), "Sanity Check");
assert(sizeof(_hash_entry_allocation_site) >= sizeof(MallocSiteHashtableEntry),
"Sanity Check");
assert((size_t)table_size <= MAX_MALLOCSITE_TABLE_SIZE, "Hashtable overflow");
assert(NMT_TrackingStackDepth > 1, "At least one tracking stack");
address pc[3];
if (NMT_TrackingStackDepth >= 3) {
uintx *fp = (uintx*)MallocSiteTable::allocation_at;
pc[2] = (address)(fp PPC64_ONLY(BIG_ENDIAN_ONLY([0])));
}
if (NMT_TrackingStackDepth >= 2) {
uintx *fp = (uintx*)MallocSiteTable::lookup_or_add;
pc[1] = (address)(fp PPC64_ONLY(BIG_ENDIAN_ONLY([0])));
}
uintx *fp = (uintx*)MallocSiteTable::new_entry;
pc[0] = (address)(fp PPC64_ONLY(BIG_ENDIAN_ONLY([0])));
NativeCallStack* stack = ::new ((void*)_hash_entry_allocation_stack)
NativeCallStack(pc, MIN2(((int)(sizeof(pc) / sizeof(address))), ((int)NMT_TrackingStackDepth)));
MallocSiteHashtableEntry* entry = ::new ((void*)_hash_entry_allocation_site)
MallocSiteHashtableEntry(*stack, mtNMT);
int index = hash_to_index(stack->hash());
_table[index] = entry;
return true;
}
bool MallocSiteTable::walk(MallocSiteWalker* walker) {
MallocSiteHashtableEntry* head;
for (int index = 0; index < table_size; index ++) {
head = _table[index];
while (head != NULL) {
if (!walker->do_malloc_site(head->peek())) {
return false;
}
head = (MallocSiteHashtableEntry*)head->next();
}
}
return true;
}
MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx,
size_t* pos_idx, MEMFLAGS flags) {
assert(flags != mtNone, "Should have a real memory type");
unsigned int index = hash_to_index(key.hash());
assert(index >= 0, "Negative index");
if (_table[index] == NULL) {
MallocSiteHashtableEntry* entry = new_entry(key, flags);
if (entry == NULL) return NULL;
if (Atomic::cmpxchg_ptr((void*)entry, (volatile void *)&_table[index], NULL) == NULL) {
return entry->data();
}
delete entry;
}
MallocSiteHashtableEntry* head = _table[index];
while (head != NULL && (*pos_idx) <= MAX_BUCKET_LENGTH) {
MallocSite* site = head->data();
if (site->flag() == flags && site->equals(key)) {
return head->data();
}
if (head->next() == NULL && (*pos_idx) < MAX_BUCKET_LENGTH) {
MallocSiteHashtableEntry* entry = new_entry(key, flags);
if (entry == NULL) return NULL;
if (head->atomic_insert(entry)) {
(*pos_idx) ++;
return entry->data();
}
delete entry;
}
head = (MallocSiteHashtableEntry*)head->next();
(*pos_idx) ++;
}
return NULL;
}
MallocSite* MallocSiteTable::malloc_site(size_t bucket_idx, size_t pos_idx) {
assert(bucket_idx < table_size, "Invalid bucket index");
MallocSiteHashtableEntry* head = _table[bucket_idx];
for (size_t index = 0; index < pos_idx && head != NULL;
index ++, head = (MallocSiteHashtableEntry*)head->next());
assert(head != NULL, "Invalid position index");
return head->data();
}
MallocSiteHashtableEntry* MallocSiteTable::new_entry(const NativeCallStack& key, MEMFLAGS flags) {
void* p = AllocateHeap(sizeof(MallocSiteHashtableEntry), mtNMT,
return ::new (p) MallocSiteHashtableEntry(key, flags);
}
void MallocSiteTable::reset() {
for (int index = 0; index < table_size; index ++) {
MallocSiteHashtableEntry* head = _table[index];
_table[index] = NULL;
delete_linked_list(head);
}
}
void MallocSiteTable::delete_linked_list(MallocSiteHashtableEntry* head) {
MallocSiteHashtableEntry* p;
while (head != NULL) {
p = head;
head = (MallocSiteHashtableEntry*)head->next();
if (p != (MallocSiteHashtableEntry*)_hash_entry_allocation_site) {
delete p;
}
}
}
void MallocSiteTable::shutdown() {
AccessLock locker(&_access_count);
locker.exclusiveLock();
reset();
}
bool MallocSiteTable::walk_malloc_site(MallocSiteWalker* walker) {
assert(walker != NULL, "NuLL walker");
AccessLock locker(&_access_count);
if (locker.sharedLock()) {
NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
return walk(walker);
}
return false;
}
void MallocSiteTable::AccessLock::exclusiveLock() {
jint target;
jint val;
assert(_lock_state != ExclusiveLock, "Can only call once");
assert(*_lock >= 0, "Can not content exclusive lock");
do {
val = *_lock;
target = _MAGIC_ + *_lock;
} while (Atomic::cmpxchg(target, _lock, val) != val);
while (*_lock != _MAGIC_) {
#ifdef _WINDOWS
os::naked_short_sleep(1);
#else
os::NakedYield();
#endif
}
_lock_state = ExclusiveLock;
}
C:\hotspot-69087d08d473\src\share\vm/services/mallocSiteTable.hpp
#ifndef SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
#define SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
#if INCLUDE_NMT
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
#include "services/allocationSite.hpp"
#include "services/mallocTracker.hpp"
#include "services/nmtCommon.hpp"
#include "utilities/nativeCallStack.hpp"
class MallocSite : public AllocationSite<MemoryCounter> {
public:
MallocSite() :
AllocationSite<MemoryCounter>(NativeCallStack::empty_stack(), mtNone) {}
MallocSite(const NativeCallStack& stack, MEMFLAGS flags) :
AllocationSite<MemoryCounter>(stack, flags) {}
void allocate(size_t size) { data()->allocate(size); }
void deallocate(size_t size) { data()->deallocate(size); }
size_t size() const { return peek()->size(); }
size_t count() const { return peek()->count(); }
};
class MallocSiteHashtableEntry : public CHeapObj<mtNMT> {
private:
MallocSite _malloc_site;
MallocSiteHashtableEntry* _next;
public:
MallocSiteHashtableEntry() : _next(NULL) { }
MallocSiteHashtableEntry(NativeCallStack stack, MEMFLAGS flags):
_malloc_site(stack, flags), _next(NULL) {
assert(flags != mtNone, "Expect a real memory type");
}
inline const MallocSiteHashtableEntry* next() const {
return _next;
}
bool atomic_insert(const MallocSiteHashtableEntry* entry) {
return (Atomic::cmpxchg_ptr((void*)entry, (volatile void*)&_next,
NULL) == NULL);
}
void set_callsite(const MallocSite& site) {
_malloc_site = site;
}
inline const MallocSite* peek() const { return &_malloc_site; }
inline MallocSite* data() { return &_malloc_site; }
inline long hash() const { return _malloc_site.hash(); }
inline bool equals(const NativeCallStack& stack) const {
return _malloc_site.equals(stack);
}
inline void allocate(size_t size) { _malloc_site.allocate(size); }
inline void deallocate(size_t size) { _malloc_site.deallocate(size); }
inline size_t size() const { return _malloc_site.size(); }
inline size_t count() const { return _malloc_site.count(); }
};
class MallocSiteWalker : public StackObj {
public:
virtual bool do_malloc_site(const MallocSite* e) { return false; }
};
class MallocSiteTable : AllStatic {
private:
enum {
table_base_size = 128, // The base size is calculated from statistics to give
table_size = (table_base_size * NMT_TrackingStackDepth - 1)
};
class AccessLock : public StackObj {
enum LockState {
NoLock,
SharedLock,
ExclusiveLock
};
private:
const static int _MAGIC_ = min_jint;
LockState _lock_state;
volatile int* _lock;
public:
AccessLock(volatile int* lock) :
_lock(lock), _lock_state(NoLock) {
}
~AccessLock() {
if (_lock_state == SharedLock) {
Atomic::dec((volatile jint*)_lock);
}
}
inline bool sharedLock() {
jint res = Atomic::add(1, _lock);
if (res < 0) {
Atomic::add(-1, _lock);
return false;
}
_lock_state = SharedLock;
return true;
}
void exclusiveLock();
};
public:
static bool initialize();
static void shutdown();
NOT_PRODUCT(static int access_peak_count() { return _peak_count; })
static inline int hash_buckets() { return (int)table_size; }
static inline bool access_stack(NativeCallStack& stack, size_t bucket_idx,
size_t pos_idx) {
AccessLock locker(&_access_count);
if (locker.sharedLock()) {
NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
MallocSite* site = malloc_site(bucket_idx, pos_idx);
if (site != NULL) {
stack = *site->call_stack();
return true;
}
}
return false;
}
static inline bool allocation_at(const NativeCallStack& stack, size_t size,
size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) {
AccessLock locker(&_access_count);
if (locker.sharedLock()) {
NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
MallocSite* site = lookup_or_add(stack, bucket_idx, pos_idx, flags);
if (site != NULL) site->allocate(size);
return site != NULL;
}
return false;
}
static inline bool deallocation_at(size_t size, size_t bucket_idx, size_t pos_idx) {
AccessLock locker(&_access_count);
if (locker.sharedLock()) {
NOT_PRODUCT(_peak_count = MAX2(_peak_count, _access_count);)
MallocSite* site = malloc_site(bucket_idx, pos_idx);
if (site != NULL) {
site->deallocate(size);
return true;
}
}
return false;
}
static bool walk_malloc_site(MallocSiteWalker* walker);
private:
static MallocSiteHashtableEntry* new_entry(const NativeCallStack& key, MEMFLAGS flags);
static void reset();
static void delete_linked_list(MallocSiteHashtableEntry* head);
static MallocSite* lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags);
static MallocSite* malloc_site(size_t bucket_idx, size_t pos_idx);
static bool walk(MallocSiteWalker* walker);
static inline unsigned int hash_to_index(unsigned int hash) {
return (hash % table_size);
}
static inline const NativeCallStack* hash_entry_allocation_stack() {
return (NativeCallStack*)_hash_entry_allocation_stack;
}
private:
static volatile int _access_count;
static MallocSiteHashtableEntry* _table[table_size];
static size_t _hash_entry_allocation_stack[CALC_OBJ_SIZE_IN_TYPE(NativeCallStack, size_t)];
static size_t _hash_entry_allocation_site[CALC_OBJ_SIZE_IN_TYPE(MallocSiteHashtableEntry, size_t)];
NOT_PRODUCT(static int _peak_count;)
};
#endif // INCLUDE_NMT
#endif // SHARE_VM_SERVICES_MALLOC_SITE_TABLE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/mallocTracker.cpp
#include "precompiled.hpp"
#include "runtime/atomic.hpp"
#include "runtime/atomic.inline.hpp"
#include "services/mallocSiteTable.hpp"
#include "services/mallocTracker.hpp"
#include "services/mallocTracker.inline.hpp"
#include "services/memTracker.hpp"
size_t MallocMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
size_t MallocMemorySnapshot::total() const {
size_t amount = 0;
for (int index = 0; index < mt_number_of_types; index ++) {
amount += _malloc[index].malloc_size();
}
amount += _tracking_header.size() + total_arena();
return amount;
}
size_t MallocMemorySnapshot::total_arena() const {
size_t amount = 0;
for (int index = 0; index < mt_number_of_types; index ++) {
amount += _malloc[index].arena_size();
}
return amount;
}
void MallocMemorySnapshot::make_adjustment() {
size_t arena_size = total_arena();
int chunk_idx = NMTUtil::flag_to_index(mtChunk);
_malloc[chunk_idx].record_free(arena_size);
}
void MallocMemorySummary::initialize() {
assert(sizeof(_snapshot) >= sizeof(MallocMemorySnapshot), "Sanity Check");
::new ((void*)_snapshot)MallocMemorySnapshot();
}
void MallocHeader::release() const {
if (MemTracker::tracking_level() <= NMT_minimal) return;
MallocMemorySummary::record_free(size(), flags());
MallocMemorySummary::record_free_malloc_header(sizeof(MallocHeader));
if (MemTracker::tracking_level() == NMT_detail) {
MallocSiteTable::deallocation_at(size(), _bucket_idx, _pos_idx);
}
}
bool MallocHeader::record_malloc_site(const NativeCallStack& stack, size_t size,
size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const {
bool ret = MallocSiteTable::allocation_at(stack, size, bucket_idx, pos_idx, flags);
if (!ret) {
MemTracker::transition_to(NMT_summary);
}
return ret;
}
bool MallocHeader::get_stack(NativeCallStack& stack) const {
return MallocSiteTable::access_stack(stack, _bucket_idx, _pos_idx);
}
bool MallocTracker::initialize(NMT_TrackingLevel level) {
if (level >= NMT_summary) {
MallocMemorySummary::initialize();
}
if (level == NMT_detail) {
return MallocSiteTable::initialize();
}
return true;
}
bool MallocTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) {
assert(from != NMT_off, "Can not transition from off state");
assert(to != NMT_off, "Can not transition to off state");
assert (from != NMT_minimal, "cannot transition from minimal state");
if (from == NMT_detail) {
assert(to == NMT_minimal || to == NMT_summary, "Just check");
MallocSiteTable::shutdown();
}
return true;
}
void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
const NativeCallStack& stack, NMT_TrackingLevel level) {
void* memblock; // the address for user data
MallocHeader* header = NULL;
if (malloc_base == NULL) {
return NULL;
}
if (level == NMT_off) {
return malloc_base;
}
header = ::new (malloc_base)MallocHeader(size, flags, stack, level);
memblock = (void*)((char*)malloc_base + sizeof(MallocHeader));
assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check");
#ifdef ASSERT
if (level > NMT_minimal) {
assert(get_size(memblock) == size, "Wrong size");
assert(get_flags(memblock) == flags, "Wrong flags");
}
#endif
return memblock;
}
void* MallocTracker::record_free(void* memblock) {
if (MemTracker::tracking_level() == NMT_off ||
memblock == NULL) {
return memblock;
}
MallocHeader* header = malloc_header(memblock);
header->release();
return (void*)header;
}
C:\hotspot-69087d08d473\src\share\vm/services/mallocTracker.hpp
#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
#define SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
#if INCLUDE_NMT
#include "memory/allocation.hpp"
#include "runtime/atomic.hpp"
#include "services/nmtCommon.hpp"
#include "utilities/nativeCallStack.hpp"
class MemoryCounter VALUE_OBJ_CLASS_SPEC {
private:
size_t _count;
size_t _size;
DEBUG_ONLY(size_t _peak_count;)
DEBUG_ONLY(size_t _peak_size; )
public:
MemoryCounter() : _count(0), _size(0) {
DEBUG_ONLY(_peak_count = 0;)
DEBUG_ONLY(_peak_size = 0;)
}
inline void allocate(size_t sz) {
Atomic::add(1, (volatile MemoryCounterType*)&_count);
if (sz > 0) {
Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
DEBUG_ONLY(_peak_size = MAX2(_peak_size, _size));
}
DEBUG_ONLY(_peak_count = MAX2(_peak_count, _count);)
}
inline void deallocate(size_t sz) {
assert(_count > 0, "Negative counter");
assert(_size >= sz, "Negative size");
Atomic::add(-1, (volatile MemoryCounterType*)&_count);
if (sz > 0) {
Atomic::add(-(MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
}
}
inline void resize(ssize_t sz) {
if (sz != 0) {
assert(sz >= 0 || _size >= size_t(-sz), "Must be");
Atomic::add((MemoryCounterType)sz, (volatile MemoryCounterType*)&_size);
DEBUG_ONLY(_peak_size = MAX2(_size, _peak_size);)
}
}
inline size_t count() const { return _count; }
inline size_t size() const { return _size; }
DEBUG_ONLY(inline size_t peak_count() const { return _peak_count; })
DEBUG_ONLY(inline size_t peak_size() const { return _peak_size; })
};
class MallocMemory VALUE_OBJ_CLASS_SPEC {
private:
MemoryCounter _malloc;
MemoryCounter _arena;
public:
MallocMemory() { }
inline void record_malloc(size_t sz) {
_malloc.allocate(sz);
}
inline void record_free(size_t sz) {
_malloc.deallocate(sz);
}
inline void record_new_arena() {
_arena.allocate(0);
}
inline void record_arena_free() {
_arena.deallocate(0);
}
inline void record_arena_size_change(ssize_t sz) {
_arena.resize(sz);
}
inline size_t malloc_size() const { return _malloc.size(); }
inline size_t malloc_count() const { return _malloc.count();}
inline size_t arena_size() const { return _arena.size(); }
inline size_t arena_count() const { return _arena.count(); }
DEBUG_ONLY(inline const MemoryCounter& malloc_counter() const { return _malloc; })
DEBUG_ONLY(inline const MemoryCounter& arena_counter() const { return _arena; })
};
class MallocMemorySummary;
class MallocMemorySnapshot : public ResourceObj {
friend class MallocMemorySummary;
private:
MallocMemory _malloc[mt_number_of_types];
MemoryCounter _tracking_header;
public:
inline MallocMemory* by_type(MEMFLAGS flags) {
int index = NMTUtil::flag_to_index(flags);
return &_malloc[index];
}
inline MallocMemory* by_index(int index) {
assert(index >= 0, "Index out of bound");
assert(index < mt_number_of_types, "Index out of bound");
return &_malloc[index];
}
inline MemoryCounter* malloc_overhead() {
return &_tracking_header;
}
size_t total() const;
size_t total_arena() const;
inline size_t thread_count() const {
MallocMemorySnapshot* s = const_cast<MallocMemorySnapshot*>(this);
return s->by_type(mtThreadStack)->malloc_count();
}
void copy_to(MallocMemorySnapshot* s) {
s->_tracking_header = _tracking_header;
for (int index = 0; index < mt_number_of_types; index ++) {
s->_malloc[index] = _malloc[index];
}
}
void make_adjustment();
};
class MallocMemorySummary : AllStatic {
private:
static size_t _snapshot[CALC_OBJ_SIZE_IN_TYPE(MallocMemorySnapshot, size_t)];
public:
static void initialize();
static inline void record_malloc(size_t size, MEMFLAGS flag) {
as_snapshot()->by_type(flag)->record_malloc(size);
}
static inline void record_free(size_t size, MEMFLAGS flag) {
as_snapshot()->by_type(flag)->record_free(size);
}
static inline void record_new_arena(MEMFLAGS flag) {
as_snapshot()->by_type(flag)->record_new_arena();
}
static inline void record_arena_free(MEMFLAGS flag) {
as_snapshot()->by_type(flag)->record_arena_free();
}
static inline void record_arena_size_change(ssize_t size, MEMFLAGS flag) {
as_snapshot()->by_type(flag)->record_arena_size_change(size);
}
static void snapshot(MallocMemorySnapshot* s) {
as_snapshot()->copy_to(s);
s->make_adjustment();
}
static inline void record_new_malloc_header(size_t sz) {
as_snapshot()->malloc_overhead()->allocate(sz);
}
static inline void record_free_malloc_header(size_t sz) {
as_snapshot()->malloc_overhead()->deallocate(sz);
}
static inline size_t tracking_overhead() {
return as_snapshot()->malloc_overhead()->size();
}
static MallocMemorySnapshot* as_snapshot() {
return (MallocMemorySnapshot*)_snapshot;
}
};
class MallocHeader VALUE_OBJ_CLASS_SPEC {
#ifdef _LP64
size_t _size : 64;
size_t _flags : 8;
size_t _pos_idx : 16;
size_t _bucket_idx: 40;
#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40)
#define MAX_BUCKET_LENGTH right_n_bits(16)
#else
size_t _size : 32;
size_t _flags : 8;
size_t _pos_idx : 8;
size_t _bucket_idx: 16;
#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(16)
#define MAX_BUCKET_LENGTH right_n_bits(8)
#endif // _LP64
public:
MallocHeader(size_t size, MEMFLAGS flags, const NativeCallStack& stack, NMT_TrackingLevel level) {
assert(sizeof(MallocHeader) == sizeof(void*) * 2,
"Wrong header size");
if (level == NMT_minimal) {
return;
}
_flags = flags;
set_size(size);
if (level == NMT_detail) {
size_t bucket_idx;
size_t pos_idx;
if (record_malloc_site(stack, size, &bucket_idx, &pos_idx, flags)) {
assert(bucket_idx <= MAX_MALLOCSITE_TABLE_SIZE, "Overflow bucket index");
assert(pos_idx <= MAX_BUCKET_LENGTH, "Overflow bucket position index");
_bucket_idx = bucket_idx;
_pos_idx = pos_idx;
}
}
MallocMemorySummary::record_malloc(size, flags);
MallocMemorySummary::record_new_malloc_header(sizeof(MallocHeader));
}
inline size_t size() const { return _size; }
inline MEMFLAGS flags() const { return (MEMFLAGS)_flags; }
bool get_stack(NativeCallStack& stack) const;
void release() const;
private:
inline void set_size(size_t size) {
_size = size;
}
bool record_malloc_site(const NativeCallStack& stack, size_t size,
size_t* bucket_idx, size_t* pos_idx, MEMFLAGS flags) const;
};
class MallocTracker : AllStatic {
public:
static bool initialize(NMT_TrackingLevel level);
static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);
static inline size_t malloc_header_size(NMT_TrackingLevel level) {
return (level == NMT_off) ? 0 : sizeof(MallocHeader);
}
static void* record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
const NativeCallStack& stack, NMT_TrackingLevel level);
static void* record_free(void* memblock);
static inline void* get_base(void* memblock);
static inline void* get_base(void* memblock, NMT_TrackingLevel level) {
if (memblock == NULL || level == NMT_off) return memblock;
return (char*)memblock - malloc_header_size(level);
}
static inline size_t get_size(void* memblock) {
MallocHeader* header = malloc_header(memblock);
return header->size();
}
static inline MEMFLAGS get_flags(void* memblock) {
MallocHeader* header = malloc_header(memblock);
return header->flags();
}
static inline size_t get_header_size(void* memblock) {
return (memblock == NULL) ? 0 : sizeof(MallocHeader);
}
static inline void record_new_arena(MEMFLAGS flags) {
MallocMemorySummary::record_new_arena(flags);
}
static inline void record_arena_free(MEMFLAGS flags) {
MallocMemorySummary::record_arena_free(flags);
}
static inline void record_arena_size_change(ssize_t size, MEMFLAGS flags) {
MallocMemorySummary::record_arena_size_change(size, flags);
}
private:
static inline MallocHeader* malloc_header(void *memblock) {
assert(memblock != NULL, "NULL pointer");
MallocHeader* header = (MallocHeader*)((char*)memblock - sizeof(MallocHeader));
return header;
}
};
#endif // INCLUDE_NMT
#endif //SHARE_VM_SERVICES_MALLOC_TRACKER_HPP
C:\hotspot-69087d08d473\src\share\vm/services/mallocTracker.inline.hpp
#ifndef SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
#define SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
#include "services/mallocTracker.hpp"
#include "services/memTracker.hpp"
inline void* MallocTracker::get_base(void* memblock){
return get_base(memblock, MemTracker::tracking_level());
}
#endif // SHARE_VM_SERVICES_MALLOC_TRACKER_INLINE_HPP
C:\hotspot-69087d08d473\src\share\vm/services/management.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/compileBroker.hpp"
#include "memory/iterator.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/klass.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/os.hpp"
#include "runtime/serviceThread.hpp"
#include "runtime/thread.inline.hpp"
#include "services/classLoadingService.hpp"
#include "services/diagnosticCommand.hpp"
#include "services/diagnosticFramework.hpp"
#include "services/heapDumper.hpp"
#include "services/jmm.h"
#include "services/lowMemoryDetector.hpp"
#include "services/gcNotifier.hpp"
#include "services/nmtDCmd.hpp"
#include "services/management.hpp"
#include "services/memoryManager.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryService.hpp"
#include "services/runtimeService.hpp"
#include "services/threadService.hpp"
#include "utilities/macros.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
PerfVariable* Management::_begin_vm_creation_time = NULL;
PerfVariable* Management::_end_vm_creation_time = NULL;
PerfVariable* Management::_vm_init_done_time = NULL;
Klass* Management::_sensor_klass = NULL;
Klass* Management::_threadInfo_klass = NULL;
Klass* Management::_memoryUsage_klass = NULL;
Klass* Management::_memoryPoolMXBean_klass = NULL;
Klass* Management::_memoryManagerMXBean_klass = NULL;
Klass* Management::_garbageCollectorMXBean_klass = NULL;
Klass* Management::_managementFactory_klass = NULL;
Klass* Management::_garbageCollectorImpl_klass = NULL;
Klass* Management::_gcInfo_klass = NULL;
Klass* Management::_diagnosticCommandImpl_klass = NULL;
Klass* Management::_managementFactoryHelper_klass = NULL;
jmmOptionalSupport Management::_optional_support = {0};
TimeStamp Management::_stamp;
void management_init() {
#if INCLUDE_MANAGEMENT
Management::init();
ThreadService::init();
RuntimeService::init();
ClassLoadingService::init();
#else
ThreadService::init();
Abstract_VM_Version::initialize();
#endif // INCLUDE_MANAGEMENT
}
#if INCLUDE_MANAGEMENT
void Management::init() {
EXCEPTION_MARK;
_begin_vm_creation_time =
PerfDataManager::create_variable(SUN_RT, "createVmBeginTime",
PerfData::U_None, CHECK);
_end_vm_creation_time =
PerfDataManager::create_variable(SUN_RT, "createVmEndTime",
PerfData::U_None, CHECK);
_vm_init_done_time =
PerfDataManager::create_variable(SUN_RT, "vmInitDoneTime",
PerfData::U_None, CHECK);
_optional_support.isLowMemoryDetectionSupported = 1;
_optional_support.isCompilationTimeMonitoringSupported = 1;
_optional_support.isThreadContentionMonitoringSupported = 1;
if (os::is_thread_cpu_time_supported()) {
_optional_support.isCurrentThreadCpuTimeSupported = 1;
_optional_support.isOtherThreadCpuTimeSupported = 1;
} else {
_optional_support.isCurrentThreadCpuTimeSupported = 0;
_optional_support.isOtherThreadCpuTimeSupported = 0;
}
_optional_support.isBootClassPathSupported = 1;
_optional_support.isObjectMonitorUsageSupported = 1;
#if INCLUDE_SERVICES
_optional_support.isSynchronizerUsageSupported = 1;
#endif // INCLUDE_SERVICES
_optional_support.isThreadAllocatedMemorySupported = 1;
_optional_support.isRemoteDiagnosticCommandsSupported = 1;
DCmdRegistrant::register_dcmds();
DCmdRegistrant::register_dcmds_ext();
uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
| DCmd_Source_MBean;
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(full_export, true, false));
}
ssssssss81
最新推荐文章于 2024-05-13 08:45:00 发布