diff options
author | zgu <none@none> | 2012-06-28 17:03:16 -0400 |
---|---|---|
committer | zgu <none@none> | 2012-06-28 17:03:16 -0400 |
commit | 81097c5596d1e5fe7b21fee4e402b4fc2ab8864a (patch) | |
tree | 627fdd6ceca133ea0a8b7c4279320af41ad70e14 /src/share/vm/runtime | |
parent | b8d56b3f5ea36ad3ac6bf98128a20aeed10546ef (diff) |
6995781: Native Memory Tracking (Phase 1)
7151532: DCmd for hotspot native memory tracking
Summary: Implementation of native memory tracking phase 1, which tracks VM native memory usage, and related DCmd
Reviewed-by: acorn, coleenp, fparain
Diffstat (limited to 'src/share/vm/runtime')
45 files changed, 422 insertions, 196 deletions
diff --git a/src/share/vm/runtime/arguments.cpp b/src/share/vm/runtime/arguments.cpp index d319fddfe..b93ef053b 100644 --- a/src/share/vm/runtime/arguments.cpp +++ b/src/share/vm/runtime/arguments.cpp @@ -35,6 +35,7 @@ #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" #include "services/management.hpp" +#include "services/memTracker.hpp" #include "utilities/defaultStream.hpp" #include "utilities/taskqueue.hpp" #ifdef TARGET_OS_FAMILY_linux @@ -368,7 +369,7 @@ inline void SysClassPath::add_suffix(const char* suffix) { inline void SysClassPath::reset_item_at(int index) { assert(index < _scp_nitems && index != _scp_base, "just checking"); if (_items[index] != NULL) { - FREE_C_HEAP_ARRAY(char, _items[index]); + FREE_C_HEAP_ARRAY(char, _items[index], mtInternal); _items[index] = NULL; } } @@ -400,11 +401,11 @@ void SysClassPath::expand_endorsed() { expanded_path = add_jars_to_path(expanded_path, path); path = end; } else { - char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1); + char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal); memcpy(dirpath, path, tmp_end - path); dirpath[tmp_end - path] = '\0'; expanded_path = add_jars_to_path(expanded_path, dirpath); - FREE_C_HEAP_ARRAY(char, dirpath); + FREE_C_HEAP_ARRAY(char, dirpath, mtInternal); path = tmp_end + 1; } } @@ -435,7 +436,7 @@ char* SysClassPath::combined_path() { assert(total_len > 0, "empty sysclasspath not allowed"); // Copy the _items to a single string. - char* cp = NEW_C_HEAP_ARRAY(char, total_len); + char* cp = NEW_C_HEAP_ARRAY(char, total_len, mtInternal); char* cp_tmp = cp; for (i = 0; i < _scp_nitems; ++i) { if (_items[i] != NULL) { @@ -456,7 +457,7 @@ SysClassPath::add_to_path(const char* path, const char* str, bool prepend) { assert(str != NULL, "just checking"); if (path == NULL) { size_t len = strlen(str) + 1; - cp = NEW_C_HEAP_ARRAY(char, len); + cp = NEW_C_HEAP_ARRAY(char, len, mtInternal); memcpy(cp, str, len); // copy the trailing null } else { const char separator = *os::path_separator(); @@ -465,15 +466,15 @@ SysClassPath::add_to_path(const char* path, const char* str, bool prepend) { size_t len = old_len + str_len + 2; if (prepend) { - cp = NEW_C_HEAP_ARRAY(char, len); + cp = NEW_C_HEAP_ARRAY(char, len, mtInternal); char* cp_tmp = cp; memcpy(cp_tmp, str, str_len); cp_tmp += str_len; *cp_tmp = separator; memcpy(++cp_tmp, path, old_len + 1); // copy the trailing null - FREE_C_HEAP_ARRAY(char, path); + FREE_C_HEAP_ARRAY(char, path, mtInternal); } else { - cp = REALLOC_C_HEAP_ARRAY(char, path, len); + cp = REALLOC_C_HEAP_ARRAY(char, path, len, mtInternal); char* cp_tmp = cp + old_len; *cp_tmp = separator; memcpy(++cp_tmp, str, str_len + 1); // copy the trailing null @@ -495,7 +496,7 @@ char* SysClassPath::add_jars_to_path(char* path, const char* directory) { /* Scan the directory for jars/zips, appending them to path. */ struct dirent *entry; - char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory)); + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal); while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { const char* name = entry->d_name; const char* ext = name + strlen(name) - 4; @@ -503,13 +504,13 @@ char* SysClassPath::add_jars_to_path(char* path, const char* directory) { (os::file_name_strcmp(ext, ".jar") == 0 || os::file_name_strcmp(ext, ".zip") == 0); if (isJarOrZip) { - char* jarpath = NEW_C_HEAP_ARRAY(char, directory_len + 2 + strlen(name)); + char* jarpath = NEW_C_HEAP_ARRAY(char, directory_len + 2 + strlen(name), mtInternal); sprintf(jarpath, "%s%s%s", directory, dir_sep, name); path = add_to_path(path, jarpath, false); - FREE_C_HEAP_ARRAY(char, jarpath); + FREE_C_HEAP_ARRAY(char, jarpath, mtInternal); } } - FREE_C_HEAP_ARRAY(char, dbuf); + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); os::closedir(dir); return path; } @@ -631,7 +632,7 @@ static bool set_numeric_flag(char* name, char* value, FlagValueOrigin origin) { static bool set_string_flag(char* name, const char* value, FlagValueOrigin origin) { if (!CommandLineFlags::ccstrAtPut(name, &value, origin)) return false; // Contract: CommandLineFlags always returns a pointer that needs freeing. - FREE_C_HEAP_ARRAY(char, value); + FREE_C_HEAP_ARRAY(char, value, mtInternal); return true; } @@ -647,7 +648,7 @@ static bool append_to_string_flag(char* name, const char* new_value, FlagValueOr } else if (new_len == 0) { value = old_value; } else { - char* buf = NEW_C_HEAP_ARRAY(char, old_len + 1 + new_len + 1); + char* buf = NEW_C_HEAP_ARRAY(char, old_len + 1 + new_len + 1, mtInternal); // each new setting adds another LINE to the switch: sprintf(buf, "%s\n%s", old_value, new_value); value = buf; @@ -655,10 +656,10 @@ static bool append_to_string_flag(char* name, const char* new_value, FlagValueOr } (void) CommandLineFlags::ccstrAtPut(name, &value, origin); // CommandLineFlags always returns a pointer that needs freeing. - FREE_C_HEAP_ARRAY(char, value); + FREE_C_HEAP_ARRAY(char, value, mtInternal); if (free_this_too != NULL) { // CommandLineFlags made its own copy, so I must delete my own temp. buffer. - FREE_C_HEAP_ARRAY(char, free_this_too); + FREE_C_HEAP_ARRAY(char, free_this_too, mtInternal); } return true; } @@ -735,9 +736,9 @@ void Arguments::add_string(char*** bldarray, int* count, const char* arg) { // expand the array and add arg to the last element (*count)++; if (*bldarray == NULL) { - *bldarray = NEW_C_HEAP_ARRAY(char*, *count); + *bldarray = NEW_C_HEAP_ARRAY(char*, *count, mtInternal); } else { - *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, *count); + *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, *count, mtInternal); } (*bldarray)[index] = strdup(arg); } @@ -917,13 +918,13 @@ bool Arguments::add_property(const char* prop) { char* value = (char *)ns; size_t key_len = (eq == NULL) ? strlen(prop) : (eq - prop); - key = AllocateHeap(key_len + 1, "add_property"); + key = AllocateHeap(key_len + 1, mtInternal); strncpy(key, prop, key_len); key[key_len] = '\0'; if (eq != NULL) { size_t value_len = strlen(prop) - key_len - 1; - value = AllocateHeap(value_len + 1, "add_property"); + value = AllocateHeap(value_len + 1, mtInternal); strncpy(value, &prop[key_len + 1], value_len + 1); } @@ -2058,12 +2059,12 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) { const char* altclasses_jar = "alt-rt.jar"; size_t altclasses_path_len = strlen(get_meta_index_dir()) + 1 + strlen(altclasses_jar); - char* altclasses_path = NEW_C_HEAP_ARRAY(char, altclasses_path_len); + char* altclasses_path = NEW_C_HEAP_ARRAY(char, altclasses_path_len, mtInternal); strcpy(altclasses_path, get_meta_index_dir()); strcat(altclasses_path, altclasses_jar); scp.add_suffix_to_prefix(altclasses_path); scp_assembly_required = true; - FREE_C_HEAP_ARRAY(char, altclasses_path); + FREE_C_HEAP_ARRAY(char, altclasses_path, mtInternal); } if (WhiteBoxAPI) { @@ -2071,12 +2072,12 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs* args) { const char* wb_jar = "wb.jar"; size_t wb_path_len = strlen(get_meta_index_dir()) + 1 + strlen(wb_jar); - char* wb_path = NEW_C_HEAP_ARRAY(char, wb_path_len); + char* wb_path = NEW_C_HEAP_ARRAY(char, wb_path_len, mtInternal); strcpy(wb_path, get_meta_index_dir()); strcat(wb_path, wb_jar); scp.add_suffix(wb_path); scp_assembly_required = true; - FREE_C_HEAP_ARRAY(char, wb_path); + FREE_C_HEAP_ARRAY(char, wb_path, mtInternal); } // Parse _JAVA_OPTIONS environment variable (if present) (mimics classic VM) @@ -2161,13 +2162,13 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (tail != NULL) { const char* pos = strchr(tail, ':'); size_t len = (pos == NULL) ? strlen(tail) : pos - tail; - char* name = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len + 1), tail, len); + char* name = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len + 1, mtInternal), tail, len); name[len] = '\0'; char *options = NULL; if(pos != NULL) { size_t len2 = strlen(pos+1) + 1; // options start after ':'. Final zero must be copied. - options = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len2), pos+1, len2); + options = (char*)memcpy(NEW_C_HEAP_ARRAY(char, len2, mtInternal), pos+1, len2); } #ifdef JVMTI_KERNEL if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { @@ -2182,12 +2183,12 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if(tail != NULL) { const char* pos = strchr(tail, '='); size_t len = (pos == NULL) ? strlen(tail) : pos - tail; - char* name = strncpy(NEW_C_HEAP_ARRAY(char, len + 1), tail, len); + char* name = strncpy(NEW_C_HEAP_ARRAY(char, len + 1, mtInternal), tail, len); name[len] = '\0'; char *options = NULL; if(pos != NULL) { - options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(pos + 1) + 1), pos + 1); + options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(pos + 1) + 1, mtInternal), pos + 1); } #ifdef JVMTI_KERNEL if ((strcmp(name, "hprof") == 0) || (strcmp(name, "jdwp") == 0)) { @@ -2200,7 +2201,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // -javaagent } else if (match_option(option, "-javaagent:", &tail)) { if(tail != NULL) { - char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1), tail); + char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail); add_init_agent("instrument", options, false); } // -Xnoclassgc @@ -2958,7 +2959,7 @@ jint Arguments::parse(const JavaVMInitArgs* args) { char *end = strrchr(jvm_path, *os::file_separator()); if (end != NULL) *end = '\0'; char *shared_archive_path = NEW_C_HEAP_ARRAY(char, strlen(jvm_path) + - strlen(os::file_separator()) + 20); + strlen(os::file_separator()) + 20, mtInternal); if (shared_archive_path == NULL) return JNI_ENOMEM; strcpy(shared_archive_path, jvm_path); strcat(shared_archive_path, os::file_separator()); @@ -2996,6 +2997,10 @@ jint Arguments::parse(const JavaVMInitArgs* args) { CommandLineFlags::printFlags(tty, false); vm_exit(0); } + if (match_option(option, "-XX:NativeMemoryTracking", &tail)) { + MemTracker::init_tracking_options(tail); + } + #ifndef PRODUCT if (match_option(option, "-XX:+PrintFlagsWithComments", &tail)) { @@ -3331,7 +3336,7 @@ char *Arguments::get_kernel_properties() { } } // Add one for null terminator. - char *props = AllocateHeap(length + 1, "get_kernel_properties"); + char *props = AllocateHeap(length + 1, mtInternal); if (length != 0) { int pos = 0; for (prop = _system_properties; prop != NULL; prop = prop->next()) { diff --git a/src/share/vm/runtime/arguments.hpp b/src/share/vm/runtime/arguments.hpp index 076b4861d..e78e45c91 100644 --- a/src/share/vm/runtime/arguments.hpp +++ b/src/share/vm/runtime/arguments.hpp @@ -44,7 +44,7 @@ class SysClassPath; // Element describing System and User (-Dkey=value flags) defined property. -class SystemProperty: public CHeapObj { +class SystemProperty: public CHeapObj<mtInternal> { private: char* _key; char* _value; @@ -63,7 +63,7 @@ class SystemProperty: public CHeapObj { if (_value != NULL) { FreeHeap(_value); } - _value = AllocateHeap(strlen(value)+1); + _value = AllocateHeap(strlen(value)+1, mtInternal); if (_value != NULL) { strcpy(_value, value); } @@ -80,7 +80,7 @@ class SystemProperty: public CHeapObj { if (_value != NULL) { len += strlen(_value); } - sp = AllocateHeap(len+2); + sp = AllocateHeap(len+2, mtInternal); if (sp != NULL) { if (_value != NULL) { strcpy(sp, _value); @@ -100,13 +100,13 @@ class SystemProperty: public CHeapObj { if (key == NULL) { _key = NULL; } else { - _key = AllocateHeap(strlen(key)+1); + _key = AllocateHeap(strlen(key)+1, mtInternal); strcpy(_key, key); } if (value == NULL) { _value = NULL; } else { - _value = AllocateHeap(strlen(value)+1); + _value = AllocateHeap(strlen(value)+1, mtInternal); strcpy(_value, value); } _next = NULL; @@ -116,7 +116,7 @@ class SystemProperty: public CHeapObj { // For use by -agentlib, -agentpath and -Xrun -class AgentLibrary : public CHeapObj { +class AgentLibrary : public CHeapObj<mtInternal> { friend class AgentLibraryList; private: char* _name; @@ -136,12 +136,12 @@ class AgentLibrary : public CHeapObj { // Constructor AgentLibrary(const char* name, const char* options, bool is_absolute_path, void* os_lib) { - _name = AllocateHeap(strlen(name)+1); + _name = AllocateHeap(strlen(name)+1, mtInternal); strcpy(_name, name); if (options == NULL) { _options = NULL; } else { - _options = AllocateHeap(strlen(options)+1); + _options = AllocateHeap(strlen(options)+1, mtInternal); strcpy(_options, options); } _is_absolute_path = is_absolute_path; diff --git a/src/share/vm/runtime/biasedLocking.cpp b/src/share/vm/runtime/biasedLocking.cpp index ba49d80de..de739ecaf 100644 --- a/src/share/vm/runtime/biasedLocking.cpp +++ b/src/share/vm/runtime/biasedLocking.cpp @@ -687,8 +687,8 @@ void BiasedLocking::preserve_marks() { // monitors in a prepass and, if they are biased, preserve their // mark words here. This should be a relatively small set of objects // especially compared to the number of objects in the heap. - _preserved_mark_stack = new (ResourceObj::C_HEAP) GrowableArray<markOop>(10, true); - _preserved_oop_stack = new (ResourceObj::C_HEAP) GrowableArray<Handle>(10, true); + _preserved_mark_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<markOop>(10, true); + _preserved_oop_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Handle>(10, true); ResourceMark rm; Thread* cur = Thread::current(); diff --git a/src/share/vm/runtime/compilationPolicy.hpp b/src/share/vm/runtime/compilationPolicy.hpp index 1d8427cf2..a0912beaf 100644 --- a/src/share/vm/runtime/compilationPolicy.hpp +++ b/src/share/vm/runtime/compilationPolicy.hpp @@ -37,7 +37,7 @@ class CompileTask; class CompileQueue; -class CompilationPolicy : public CHeapObj { +class CompilationPolicy : public CHeapObj<mtCompiler> { static CompilationPolicy* _policy; // Accumulated time static elapsedTimer _accumulated_time; diff --git a/src/share/vm/runtime/deoptimization.cpp b/src/share/vm/runtime/deoptimization.cpp index 0e2a9839b..bbb5bc3cc 100644 --- a/src/share/vm/runtime/deoptimization.cpp +++ b/src/share/vm/runtime/deoptimization.cpp @@ -101,7 +101,7 @@ Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, _number_of_frames = number_of_frames; _frame_sizes = frame_sizes; _frame_pcs = frame_pcs; - _register_block = NEW_C_HEAP_ARRAY(intptr_t, RegisterMap::reg_count * 2); + _register_block = NEW_C_HEAP_ARRAY(intptr_t, RegisterMap::reg_count * 2, mtCompiler); _return_type = return_type; _initial_info = 0; // PD (x86 only) @@ -114,9 +114,9 @@ Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, Deoptimization::UnrollBlock::~UnrollBlock() { - FREE_C_HEAP_ARRAY(intptr_t, _frame_sizes); - FREE_C_HEAP_ARRAY(intptr_t, _frame_pcs); - FREE_C_HEAP_ARRAY(intptr_t, _register_block); + FREE_C_HEAP_ARRAY(intptr_t, _frame_sizes, mtCompiler); + FREE_C_HEAP_ARRAY(intptr_t, _frame_pcs, mtCompiler); + FREE_C_HEAP_ARRAY(intptr_t, _register_block, mtCompiler); } @@ -358,9 +358,9 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread // Compute the vframes' sizes. Note that frame_sizes[] entries are ordered from outermost to innermost // virtual activation, which is the reverse of the elements in the vframes array. - intptr_t* frame_sizes = NEW_C_HEAP_ARRAY(intptr_t, number_of_frames); + intptr_t* frame_sizes = NEW_C_HEAP_ARRAY(intptr_t, number_of_frames, mtCompiler); // +1 because we always have an interpreter return address for the final slot. - address* frame_pcs = NEW_C_HEAP_ARRAY(address, number_of_frames + 1); + address* frame_pcs = NEW_C_HEAP_ARRAY(address, number_of_frames + 1, mtCompiler); int popframe_extra_args = 0; // Create an interpreter return address for the stub to use as its return // address so the skeletal frames are perfectly walkable diff --git a/src/share/vm/runtime/deoptimization.hpp b/src/share/vm/runtime/deoptimization.hpp index 182254679..23870b4e8 100644 --- a/src/share/vm/runtime/deoptimization.hpp +++ b/src/share/vm/runtime/deoptimization.hpp @@ -129,7 +129,7 @@ class Deoptimization : AllStatic { // UnrollBlock is returned by fetch_unroll_info() to the deoptimization handler (blob). // This is only a CheapObj to ease debugging after a deopt failure - class UnrollBlock : public CHeapObj { + class UnrollBlock : public CHeapObj<mtCompiler> { private: int _size_of_deoptimized_frame; // Size, in bytes, of current deoptimized frame int _caller_adjustment; // Adjustment, in bytes, to caller's SP by initial interpreted frame diff --git a/src/share/vm/runtime/dtraceJSDT.hpp b/src/share/vm/runtime/dtraceJSDT.hpp index bff431084..670eabfef 100644 --- a/src/share/vm/runtime/dtraceJSDT.hpp +++ b/src/share/vm/runtime/dtraceJSDT.hpp @@ -63,7 +63,7 @@ class DTraceJSDT : AllStatic { static jboolean is_supported(); }; -class RegisteredProbes : public CHeapObj { +class RegisteredProbes : public CHeapObj<mtInternal> { private: nmethod** _nmethods; // all the probe methods size_t _count; // number of probe methods @@ -72,7 +72,7 @@ class RegisteredProbes : public CHeapObj { public: RegisteredProbes(size_t count) { _count = count; - _nmethods = NEW_C_HEAP_ARRAY(nmethod*, count); + _nmethods = NEW_C_HEAP_ARRAY(nmethod*, count, mtInternal); } ~RegisteredProbes() { @@ -81,7 +81,7 @@ class RegisteredProbes : public CHeapObj { _nmethods[i]->make_not_entrant(); _nmethods[i]->method()->clear_code(); } - FREE_C_HEAP_ARRAY(nmethod*, _nmethods); + FREE_C_HEAP_ARRAY(nmethod*, _nmethods, mtInternal); _nmethods = NULL; _count = 0; } diff --git a/src/share/vm/runtime/fprofiler.cpp b/src/share/vm/runtime/fprofiler.cpp index 3c100aa4c..9901fb9fa 100644 --- a/src/share/vm/runtime/fprofiler.cpp +++ b/src/share/vm/runtime/fprofiler.cpp @@ -70,12 +70,12 @@ IntervalData* FlatProfiler::interval_data = NULL; ThreadProfiler::ThreadProfiler() { // Space for the ProfilerNodes const int area_size = 1 * ProfilerNodeSize * 1024; - area_bottom = AllocateHeap(area_size, "fprofiler"); + area_bottom = AllocateHeap(area_size, mtInternal); area_top = area_bottom; area_limit = area_bottom + area_size; // ProfilerNode pointer table - table = NEW_C_HEAP_ARRAY(ProfilerNode*, table_size); + table = NEW_C_HEAP_ARRAY(ProfilerNode*, table_size, mtInternal); initialize(); engaged = false; } @@ -157,7 +157,7 @@ address PCRecorder::base = NULL; void PCRecorder::init() { MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag); int s = size(); - counters = NEW_C_HEAP_ARRAY(int, s); + counters = NEW_C_HEAP_ARRAY(int, s, mtInternal); for (int index = 0; index < s; index++) { counters[index] = 0; } @@ -850,7 +850,7 @@ void FlatProfiler::record_thread_ticks() { if (Threads_lock->try_lock()) { { // Threads_lock scope maxthreads = Threads::number_of_threads(); - threadsList = NEW_C_HEAP_ARRAY(JavaThread *, maxthreads); + threadsList = NEW_C_HEAP_ARRAY(JavaThread *, maxthreads, mtInternal); suspendedthreadcount = 0; for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) { if (tp->is_Compiler_thread()) { @@ -1195,8 +1195,8 @@ void ThreadProfiler::reset() { void FlatProfiler::allocate_table() { { // Bytecode table - bytecode_ticks = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes); - bytecode_ticks_stub = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes); + bytecode_ticks = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal); + bytecode_ticks_stub = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal); for(int index = 0; index < Bytecodes::number_of_codes; index++) { bytecode_ticks[index] = 0; bytecode_ticks_stub[index] = 0; @@ -1205,7 +1205,7 @@ void FlatProfiler::allocate_table() { if (ProfilerRecordPC) PCRecorder::init(); - interval_data = NEW_C_HEAP_ARRAY(IntervalData, interval_print_size); + interval_data = NEW_C_HEAP_ARRAY(IntervalData, interval_print_size, mtInternal); FlatProfiler::interval_reset(); } diff --git a/src/share/vm/runtime/fprofiler.hpp b/src/share/vm/runtime/fprofiler.hpp index 2f8d6158c..25c2f2a10 100644 --- a/src/share/vm/runtime/fprofiler.hpp +++ b/src/share/vm/runtime/fprofiler.hpp @@ -121,7 +121,7 @@ public: }; #endif // FPROF_KERNEL -class ThreadProfiler: public CHeapObj { +class ThreadProfiler: public CHeapObj<mtInternal> { public: ThreadProfiler() KERNEL_RETURN; ~ThreadProfiler() KERNEL_RETURN; diff --git a/src/share/vm/runtime/globals.cpp b/src/share/vm/runtime/globals.cpp index 474090a2a..3dad7a0f0 100644 --- a/src/share/vm/runtime/globals.cpp +++ b/src/share/vm/runtime/globals.cpp @@ -465,13 +465,13 @@ bool CommandLineFlags::ccstrAtPut(char* name, size_t len, ccstr* value, FlagValu ccstr old_value = result->get_ccstr(); char* new_value = NULL; if (*value != NULL) { - new_value = NEW_C_HEAP_ARRAY(char, strlen(*value)+1); + new_value = NEW_C_HEAP_ARRAY(char, strlen(*value)+1, mtInternal); strcpy(new_value, *value); } result->set_ccstr(new_value); if (result->origin == DEFAULT && old_value != NULL) { // Prior value is NOT heap allocated, but was a literal constant. - char* old_value_to_free = NEW_C_HEAP_ARRAY(char, strlen(old_value)+1); + char* old_value_to_free = NEW_C_HEAP_ARRAY(char, strlen(old_value)+1, mtInternal); strcpy(old_value_to_free, old_value); old_value = old_value_to_free; } @@ -485,12 +485,12 @@ void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, F Flag* faddr = address_of_flag(flag); guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type"); ccstr old_value = faddr->get_ccstr(); - char* new_value = NEW_C_HEAP_ARRAY(char, strlen(value)+1); + char* new_value = NEW_C_HEAP_ARRAY(char, strlen(value)+1, mtInternal); strcpy(new_value, value); faddr->set_ccstr(new_value); if (faddr->origin != DEFAULT && old_value != NULL) { // Prior value is heap allocated so free it. - FREE_C_HEAP_ARRAY(char, old_value); + FREE_C_HEAP_ARRAY(char, old_value, mtInternal); } faddr->origin = origin; } @@ -511,7 +511,7 @@ void CommandLineFlags::printSetFlags(outputStream* out) { while (flagTable[length].name != NULL) length++; // Sort - Flag** array = NEW_C_HEAP_ARRAY(Flag*, length); + Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal); for (int index = 0; index < length; index++) { array[index] = &flagTable[index]; } @@ -525,7 +525,7 @@ void CommandLineFlags::printSetFlags(outputStream* out) { } } out->cr(); - FREE_C_HEAP_ARRAY(Flag*, array); + FREE_C_HEAP_ARRAY(Flag*, array, mtInternal); } #ifndef PRODUCT @@ -547,7 +547,7 @@ void CommandLineFlags::printFlags(outputStream* out, bool withComments) { while (flagTable[length].name != NULL) length++; // Sort - Flag** array = NEW_C_HEAP_ARRAY(Flag*, length); + Flag** array = NEW_C_HEAP_ARRAY(Flag*, length, mtInternal); for (int index = 0; index < length; index++) { array[index] = &flagTable[index]; } @@ -560,5 +560,5 @@ void CommandLineFlags::printFlags(outputStream* out, bool withComments) { array[i]->print_on(out, withComments); } } - FREE_C_HEAP_ARRAY(Flag*, array); + FREE_C_HEAP_ARRAY(Flag*, array, mtInternal); } diff --git a/src/share/vm/runtime/globals.hpp b/src/share/vm/runtime/globals.hpp index a961a151c..504c4061c 100644 --- a/src/share/vm/runtime/globals.hpp +++ b/src/share/vm/runtime/globals.hpp @@ -190,7 +190,6 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G); #endif // no compilers - // string type aliases used only in this file typedef const char* ccstr; typedef const char* ccstrlist; // represents string arguments which accumulate @@ -896,6 +895,9 @@ class CommandLineFlags { develop(bool, UseFakeTimers, false, \ "Tells whether the VM should use system time or a fake timer") \ \ + product(ccstr, NativeMemoryTracking, "off", \ + "Native memory tracking options") \ + \ diagnostic(bool, LogCompilation, false, \ "Log compilation activity in detail to hotspot.log or LogFile") \ \ diff --git a/src/share/vm/runtime/handles.cpp b/src/share/vm/runtime/handles.cpp index 3c24f81ce..1ddbacc44 100644 --- a/src/share/vm/runtime/handles.cpp +++ b/src/share/vm/runtime/handles.cpp @@ -111,7 +111,7 @@ void HandleMark::initialize(Thread* thread) { _chunk = _area->_chunk; _hwm = _area->_hwm; _max = _area->_max; - NOT_PRODUCT(_size_in_bytes = _area->_size_in_bytes;) + _size_in_bytes = _area->_size_in_bytes; debug_only(_area->_handle_mark_nesting++); assert(_area->_handle_mark_nesting > 0, "must stack allocate HandleMarks"); debug_only(Atomic::inc(&_nof_handlemarks);) @@ -159,7 +159,7 @@ HandleMark::~HandleMark() { area->_chunk = _chunk; area->_hwm = _hwm; area->_max = _max; - NOT_PRODUCT(area->set_size_in_bytes(_size_in_bytes);) + area->set_size_in_bytes(_size_in_bytes); #ifdef ASSERT // clear out first chunk (to detect allocation bugs) if (ZapVMHandleArea) { diff --git a/src/share/vm/runtime/handles.hpp b/src/share/vm/runtime/handles.hpp index d9d71e670..e2b2d4971 100644 --- a/src/share/vm/runtime/handles.hpp +++ b/src/share/vm/runtime/handles.hpp @@ -238,7 +238,6 @@ DEF_KLASS_HANDLE(constantPoolCacheKlass, oop_is_constantPool ) //------------------------------------------------------------------------------------------------------------------------ // Thread local handle area - class HandleArea: public Arena { friend class HandleMark; friend class NoHandleMark; @@ -312,7 +311,7 @@ class HandleMark { HandleArea *_area; // saved handle area Chunk *_chunk; // saved arena chunk char *_hwm, *_max; // saved arena info - NOT_PRODUCT(size_t _size_in_bytes;) // size of handle area + size_t _size_in_bytes; // size of handle area // Link to previous active HandleMark in thread HandleMark* _previous_handle_mark; diff --git a/src/share/vm/runtime/handles.inline.hpp b/src/share/vm/runtime/handles.inline.hpp index 3bd42fb2e..806d66fca 100644 --- a/src/share/vm/runtime/handles.inline.hpp +++ b/src/share/vm/runtime/handles.inline.hpp @@ -85,7 +85,7 @@ inline void HandleMark::pop_and_restore() { area->_chunk = _chunk; area->_hwm = _hwm; area->_max = _max; - NOT_PRODUCT(area->set_size_in_bytes(_size_in_bytes);) + area->set_size_in_bytes(_size_in_bytes); debug_only(area->_handle_mark_nesting--); } diff --git a/src/share/vm/runtime/java.cpp b/src/share/vm/runtime/java.cpp index f256e515e..70c9e2895 100644 --- a/src/share/vm/runtime/java.cpp +++ b/src/share/vm/runtime/java.cpp @@ -384,7 +384,7 @@ extern "C" { typedef void (*__exit_proc)(void); } -class ExitProc : public CHeapObj { +class ExitProc : public CHeapObj<mtInternal> { private: __exit_proc _proc; // void (*_proc)(void); diff --git a/src/share/vm/runtime/jniHandles.hpp b/src/share/vm/runtime/jniHandles.hpp index a3b2f9c4c..71bb1dd89 100644 --- a/src/share/vm/runtime/jniHandles.hpp +++ b/src/share/vm/runtime/jniHandles.hpp @@ -109,7 +109,7 @@ class JNIHandles : AllStatic { // JNI handle blocks holding local/global JNI handles -class JNIHandleBlock : public CHeapObj { +class JNIHandleBlock : public CHeapObj<mtInternal> { friend class VMStructs; friend class CppInterpreter; diff --git a/src/share/vm/runtime/monitorChunk.cpp b/src/share/vm/runtime/monitorChunk.cpp index 1a4be7920..f8793fdea 100644 --- a/src/share/vm/runtime/monitorChunk.cpp +++ b/src/share/vm/runtime/monitorChunk.cpp @@ -29,7 +29,7 @@ MonitorChunk::MonitorChunk(int number_on_monitors) { _number_of_monitors = number_on_monitors; - _monitors = NEW_C_HEAP_ARRAY(BasicObjectLock, number_on_monitors); + _monitors = NEW_C_HEAP_ARRAY(BasicObjectLock, number_on_monitors, mtInternal); _next = NULL; } diff --git a/src/share/vm/runtime/monitorChunk.hpp b/src/share/vm/runtime/monitorChunk.hpp index 66d62438c..eca92a6b4 100644 --- a/src/share/vm/runtime/monitorChunk.hpp +++ b/src/share/vm/runtime/monitorChunk.hpp @@ -30,7 +30,7 @@ // Data structure for holding monitors for one activation during // deoptimization. -class MonitorChunk: public CHeapObj { +class MonitorChunk: public CHeapObj<mtInternal> { private: int _number_of_monitors; BasicObjectLock* _monitors; diff --git a/src/share/vm/runtime/mutex.hpp b/src/share/vm/runtime/mutex.hpp index 66a3295c8..7d2cd8272 100644 --- a/src/share/vm/runtime/mutex.hpp +++ b/src/share/vm/runtime/mutex.hpp @@ -84,7 +84,7 @@ class ParkEvent ; // The default length of monitor name is chosen to be 64 to avoid false sharing. static const int MONITOR_NAME_LEN = 64; -class Monitor : public CHeapObj { +class Monitor : public CHeapObj<mtInternal> { public: // A special lock: Is a lock where you are guaranteed not to block while you are diff --git a/src/share/vm/runtime/os.cpp b/src/share/vm/runtime/os.cpp index 33495d66d..d9395b3ad 100644 --- a/src/share/vm/runtime/os.cpp +++ b/src/share/vm/runtime/os.cpp @@ -45,6 +45,7 @@ #include "runtime/os.hpp" #include "runtime/stubRoutines.hpp" #include "services/attachListener.hpp" +#include "services/memTracker.hpp" #include "services/threadService.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" @@ -433,9 +434,9 @@ void* os::native_java_library() { // --------------------- heap allocation utilities --------------------- -char *os::strdup(const char *str) { +char *os::strdup(const char *str, MEMFLAGS flags) { size_t size = strlen(str); - char *dup_str = (char *)malloc(size + 1); + char *dup_str = (char *)malloc(size + 1, flags); if (dup_str == NULL) return NULL; strcpy(dup_str, str); return dup_str; @@ -559,7 +560,7 @@ void verify_block(void* memblock) { } #endif -void* os::malloc(size_t size) { +void* os::malloc(size_t size, MEMFLAGS memflags, address caller) { NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); @@ -571,6 +572,7 @@ void* os::malloc(size_t size) { NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap()); u_char* ptr = (u_char*)::malloc(size + space_before + space_after); + #ifdef ASSERT if (ptr == NULL) return NULL; if (MallocCushion) { @@ -589,18 +591,29 @@ void* os::malloc(size_t size) { } debug_only(if (paranoid) verify_block(memblock)); if (PrintMalloc && tty != NULL) tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, memblock); + + // we do not track MallocCushion memory + if (MemTracker::is_on()) { + MemTracker::record_malloc((address)memblock, size, memflags, caller == 0 ? CALLER_PC : caller); + } + return memblock; } -void* os::realloc(void *memblock, size_t size) { +void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, address caller) { #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); - return ::realloc(memblock, size); + void* ptr = ::realloc(memblock, size); + if (ptr != NULL && MemTracker::is_on()) { + MemTracker::record_realloc((address)memblock, (address)ptr, size, memflags, + caller == 0 ? CALLER_PC : caller); + } + return ptr; #else if (memblock == NULL) { - return malloc(size); + return malloc(size, memflags, (caller == 0 ? CALLER_PC : caller)); } if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) { tty->print_cr("os::realloc caught " PTR_FORMAT, memblock); @@ -610,7 +623,7 @@ void* os::realloc(void *memblock, size_t size) { NOT_PRODUCT(if (MallocVerifyInterval > 0) check_heap()); if (size == 0) return NULL; // always move the block - void* ptr = malloc(size); + void* ptr = malloc(size, memflags, caller == 0 ? CALLER_PC : caller); if (PrintMalloc) tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr); // Copy to new memory if malloc didn't fail if ( ptr != NULL ) { @@ -627,7 +640,7 @@ void* os::realloc(void *memblock, size_t size) { } -void os::free(void *memblock) { +void os::free(void *memblock, MEMFLAGS memflags) { NOT_PRODUCT(inc_stat_counter(&num_frees, 1)); #ifdef ASSERT if (memblock == NULL) return; @@ -660,6 +673,8 @@ void os::free(void *memblock) { fprintf(stderr, "os::free " PTR_FORMAT "\n", (uintptr_t)memblock); } #endif + MemTracker::record_free((address)memblock, memflags); + ::free((char*)memblock - space_before); } @@ -1048,7 +1063,7 @@ char* os::format_boot_path(const char* format_string, ++formatted_path_len; } - char* formatted_path = NEW_C_HEAP_ARRAY(char, formatted_path_len + 1); + char* formatted_path = NEW_C_HEAP_ARRAY(char, formatted_path_len + 1, mtInternal); if (formatted_path == NULL) { return NULL; } @@ -1127,7 +1142,7 @@ char** os::split_path(const char* path, int* n) { return NULL; } const char psepchar = *os::path_separator(); - char* inpath = (char*)NEW_C_HEAP_ARRAY(char, strlen(path) + 1); + char* inpath = (char*)NEW_C_HEAP_ARRAY(char, strlen(path) + 1, mtInternal); if (inpath == NULL) { return NULL; } @@ -1140,7 +1155,7 @@ char** os::split_path(const char* path, int* n) { p++; p = strchr(p, psepchar); } - char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count); + char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count, mtInternal); if (opath == NULL) { return NULL; } @@ -1153,7 +1168,7 @@ char** os::split_path(const char* path, int* n) { return NULL; } // allocate the string and add terminator storage - char* s = (char*)NEW_C_HEAP_ARRAY(char, len + 1); + char* s = (char*)NEW_C_HEAP_ARRAY(char, len + 1, mtInternal); if (s == NULL) { return NULL; } @@ -1162,7 +1177,7 @@ char** os::split_path(const char* path, int* n) { opath[i] = s; p += len + 1; } - FREE_C_HEAP_ARRAY(char, inpath); + FREE_C_HEAP_ARRAY(char, inpath, mtInternal); *n = count; return opath; } @@ -1366,3 +1381,97 @@ int os::get_line_chars(int fd, char* buf, const size_t bsize){ return (int) i; } + +bool os::create_stack_guard_pages(char* addr, size_t bytes) { + return os::pd_create_stack_guard_pages(addr, bytes); +} + + +char* os::reserve_memory(size_t bytes, char* addr, size_t alignment_hint) { + char* result = pd_reserve_memory(bytes, addr, alignment_hint); + if (result != NULL && MemTracker::is_on()) { + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + } + + return result; +} +char* os::attempt_reserve_memory_at(size_t bytes, char* addr) { + char* result = pd_attempt_reserve_memory_at(bytes, addr); + if (result != NULL && MemTracker::is_on()) { + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + } + return result; +} + +void os::split_reserved_memory(char *base, size_t size, + size_t split, bool realloc) { + pd_split_reserved_memory(base, size, split, realloc); +} + +bool os::commit_memory(char* addr, size_t bytes, bool executable) { + bool res = pd_commit_memory(addr, bytes, executable); + if (res && MemTracker::is_on()) { + MemTracker::record_virtual_memory_commit((address)addr, bytes, CALLER_PC); + } + return res; +} + +bool os::commit_memory(char* addr, size_t size, size_t alignment_hint, + bool executable) { + bool res = os::pd_commit_memory(addr, size, alignment_hint, executable); + if (res && MemTracker::is_on()) { + MemTracker::record_virtual_memory_commit((address)addr, size, CALLER_PC); + } + return res; +} + +bool os::uncommit_memory(char* addr, size_t bytes) { + bool res = pd_uncommit_memory(addr, bytes); + if (res) { + MemTracker::record_virtual_memory_uncommit((address)addr, bytes); + } + return res; +} + +bool os::release_memory(char* addr, size_t bytes) { + bool res = pd_release_memory(addr, bytes); + if (res) { + MemTracker::record_virtual_memory_release((address)addr, bytes); + } + return res; +} + + +char* os::map_memory(int fd, const char* file_name, size_t file_offset, + char *addr, size_t bytes, bool read_only, + bool allow_exec) { + char* result = pd_map_memory(fd, file_name, file_offset, addr, bytes, read_only, allow_exec); + if (result != NULL && MemTracker::is_on()) { + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); + } + return result; +} + +char* os::remap_memory(int fd, const char* file_name, size_t file_offset, + char *addr, size_t bytes, bool read_only, + bool allow_exec) { + return pd_remap_memory(fd, file_name, file_offset, addr, bytes, + read_only, allow_exec); +} + +bool os::unmap_memory(char *addr, size_t bytes) { + bool result = pd_unmap_memory(addr, bytes); + if (result) { + MemTracker::record_virtual_memory_release((address)addr, bytes); + } + return result; +} + +void os::free_memory(char *addr, size_t bytes, size_t alignment_hint) { + pd_free_memory(addr, bytes, alignment_hint); +} + +void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { + pd_realign_memory(addr, bytes, alignment_hint); +} + diff --git a/src/share/vm/runtime/os.hpp b/src/share/vm/runtime/os.hpp index 68f8a3ab6..3be7248a9 100644 --- a/src/share/vm/runtime/os.hpp +++ b/src/share/vm/runtime/os.hpp @@ -99,6 +99,28 @@ class os: AllStatic { _page_sizes[1] = 0; // sentinel } + static char* pd_reserve_memory(size_t bytes, char* addr = 0, + size_t alignment_hint = 0); + static char* pd_attempt_reserve_memory_at(size_t bytes, char* addr); + static void pd_split_reserved_memory(char *base, size_t size, + size_t split, bool realloc); + static bool pd_commit_memory(char* addr, size_t bytes, bool executable = false); + static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint, + bool executable = false); + static bool pd_uncommit_memory(char* addr, size_t bytes); + static bool pd_release_memory(char* addr, size_t bytes); + + static char* pd_map_memory(int fd, const char* file_name, size_t file_offset, + char *addr, size_t bytes, bool read_only = false, + bool allow_exec = false); + static char* pd_remap_memory(int fd, const char* file_name, size_t file_offset, + char *addr, size_t bytes, bool read_only, + bool allow_exec); + static bool pd_unmap_memory(char *addr, size_t bytes); + static void pd_free_memory(char *addr, size_t bytes, size_t alignment_hint); + static void pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint); + + public: static void init(void); // Called before command line parsing static jint init_2(void); // Called after command line parsing @@ -236,8 +258,7 @@ class os: AllStatic { static char* attempt_reserve_memory_at(size_t bytes, char* addr); static void split_reserved_memory(char *base, size_t size, size_t split, bool realloc); - static bool commit_memory(char* addr, size_t bytes, - bool executable = false); + static bool commit_memory(char* addr, size_t bytes, bool executable = false); static bool commit_memory(char* addr, size_t size, size_t alignment_hint, bool executable = false); static bool uncommit_memory(char* addr, size_t bytes); @@ -250,6 +271,7 @@ class os: AllStatic { static bool guard_memory(char* addr, size_t bytes); static bool unguard_memory(char* addr, size_t bytes); static bool create_stack_guard_pages(char* addr, size_t bytes); + static bool pd_create_stack_guard_pages(char* addr, size_t bytes); static bool remove_stack_guard_pages(char* addr, size_t bytes); static char* map_memory(int fd, const char* file_name, size_t file_offset, @@ -573,12 +595,15 @@ class os: AllStatic { static void* thread_local_storage_at(int index); static void free_thread_local_storage(int index); + // Stack walk + static address get_caller_pc(int n = 0); + // General allocation (must be MT-safe) - static void* malloc (size_t size); - static void* realloc (void *memblock, size_t size); - static void free (void *memblock); + static void* malloc (size_t size, MEMFLAGS flags, address caller_pc = 0); + static void* realloc (void *memblock, size_t size, MEMFLAGS flags, address caller_pc = 0); + static void free (void *memblock, MEMFLAGS flags = mtNone); static bool check_heap(bool force = false); // verify C heap integrity - static char* strdup(const char *); // Like strdup + static char* strdup(const char *, MEMFLAGS flags = mtInternal); // Like strdup #ifndef PRODUCT static julong num_mallocs; // # of calls to malloc/realloc diff --git a/src/share/vm/runtime/osThread.hpp b/src/share/vm/runtime/osThread.hpp index c0f2b1932..1dfcb3761 100644 --- a/src/share/vm/runtime/osThread.hpp +++ b/src/share/vm/runtime/osThread.hpp @@ -58,7 +58,7 @@ enum ThreadState { // the main thread into its own Thread at will. -class OSThread: public CHeapObj { +class OSThread: public CHeapObj<mtThread> { friend class VMStructs; private: OSThreadStartFunc _start_proc; // Thread start routine diff --git a/src/share/vm/runtime/park.cpp b/src/share/vm/runtime/park.cpp index 1be573332..8d91d0b68 100644 --- a/src/share/vm/runtime/park.cpp +++ b/src/share/vm/runtime/park.cpp @@ -141,7 +141,7 @@ void ParkEvent::Release (ParkEvent * ev) { // although Niagara's hash function should help. void * ParkEvent::operator new (size_t sz) { - return (void *) ((intptr_t (CHeapObj::operator new (sz + 256)) + 256) & -256) ; + return (void *) ((intptr_t (AllocateHeap(sz + 256, mtInternal, CALLER_PC)) + 256) & -256) ; } void ParkEvent::operator delete (void * a) { diff --git a/src/share/vm/runtime/perfData.cpp b/src/share/vm/runtime/perfData.cpp index 04631ec26..3d4bf2da8 100644 --- a/src/share/vm/runtime/perfData.cpp +++ b/src/share/vm/runtime/perfData.cpp @@ -81,7 +81,7 @@ PerfData::PerfData(CounterNS ns, const char* name, Units u, Variability v) const char* prefix = PerfDataManager::ns_to_string(ns); - _name = NEW_C_HEAP_ARRAY(char, strlen(name) + strlen(prefix) + 2); + _name = NEW_C_HEAP_ARRAY(char, strlen(name) + strlen(prefix) + 2, mtInternal); assert(_name != NULL && strlen(name) != 0, "invalid name"); if (ns == NULL_NS) { @@ -111,10 +111,10 @@ PerfData::PerfData(CounterNS ns, const char* name, Units u, Variability v) PerfData::~PerfData() { if (_name != NULL) { - FREE_C_HEAP_ARRAY(char, _name); + FREE_C_HEAP_ARRAY(char, _name, mtInternal); } if (is_on_c_heap()) { - FREE_C_HEAP_ARRAY(PerfDataEntry, _pdep); + FREE_C_HEAP_ARRAY(PerfDataEntry, _pdep, mtInternal); } } @@ -137,7 +137,7 @@ void PerfData::create_entry(BasicType dtype, size_t dsize, size_t vlen) { if (psmp == NULL) { // out of PerfMemory memory resources. allocate on the C heap // to avoid vm termination. - psmp = NEW_C_HEAP_ARRAY(char, size); + psmp = NEW_C_HEAP_ARRAY(char, size, mtInternal); _on_c_heap = true; } @@ -559,12 +559,12 @@ PerfLongCounter* PerfDataManager::create_long_counter(CounterNS ns, PerfDataList::PerfDataList(int length) { - _set = new(ResourceObj::C_HEAP) PerfDataArray(length, true); + _set = new(ResourceObj::C_HEAP, mtInternal) PerfDataArray(length, true); } PerfDataList::PerfDataList(PerfDataList* p) { - _set = new(ResourceObj::C_HEAP) PerfDataArray(p->length(), true); + _set = new(ResourceObj::C_HEAP, mtInternal) PerfDataArray(p->length(), true); _set->appendAll(p->get_impl()); } diff --git a/src/share/vm/runtime/perfData.hpp b/src/share/vm/runtime/perfData.hpp index 2f84ee620..2552fe8ba 100644 --- a/src/share/vm/runtime/perfData.hpp +++ b/src/share/vm/runtime/perfData.hpp @@ -240,7 +240,7 @@ enum CounterNS { * be removed from the product in the future. * */ -class PerfData : public CHeapObj { +class PerfData : public CHeapObj<mtInternal> { friend class StatSampler; // for access to protected void sample() friend class PerfDataManager; // for access to protected destructor @@ -342,7 +342,7 @@ class PerfData : public CHeapObj { * invoke the take_sample() method and write the value returned to its * appropriate location in the PerfData memory region. */ -class PerfLongSampleHelper : public CHeapObj { +class PerfLongSampleHelper : public CHeapObj<mtInternal> { public: virtual jlong take_sample() = 0; }; @@ -591,7 +591,7 @@ class PerfStringVariable : public PerfString { * some other implementation, as long as that implementation provides * a mechanism to iterate over the container by index. */ -class PerfDataList : public CHeapObj { +class PerfDataList : public CHeapObj<mtInternal> { private: diff --git a/src/share/vm/runtime/perfMemory.cpp b/src/share/vm/runtime/perfMemory.cpp index 0855b38c9..26ef55e5f 100644 --- a/src/share/vm/runtime/perfMemory.cpp +++ b/src/share/vm/runtime/perfMemory.cpp @@ -112,7 +112,7 @@ void PerfMemory::initialize() { warning("Could not create PerfData Memory region, reverting to malloc"); } - _prologue = NEW_C_HEAP_OBJ(PerfDataPrologue); + _prologue = NEW_C_HEAP_OBJ(PerfDataPrologue, mtInternal); } else { @@ -244,10 +244,10 @@ char* PerfMemory::get_perfdata_file_path() { if (PerfDataSaveFile != NULL) { // dest_file_name stores the validated file name if file_name // contains %p which will be replaced by pid. - dest_file = NEW_C_HEAP_ARRAY(char, JVM_MAXPATHLEN); + dest_file = NEW_C_HEAP_ARRAY(char, JVM_MAXPATHLEN, mtInternal); if(!Arguments::copy_expand_pid(PerfDataSaveFile, strlen(PerfDataSaveFile), dest_file, JVM_MAXPATHLEN)) { - FREE_C_HEAP_ARRAY(char, dest_file); + FREE_C_HEAP_ARRAY(char, dest_file, mtInternal); if (PrintMiscellaneous && Verbose) { warning("Invalid performance data file path name specified, "\ "fall back to a default name"); @@ -257,7 +257,7 @@ char* PerfMemory::get_perfdata_file_path() { } } // create the name of the file for retaining the instrumentation memory. - dest_file = NEW_C_HEAP_ARRAY(char, PERFDATA_FILENAME_LEN); + dest_file = NEW_C_HEAP_ARRAY(char, PERFDATA_FILENAME_LEN, mtInternal); jio_snprintf(dest_file, PERFDATA_FILENAME_LEN, "%s_%d", PERFDATA_NAME, os::current_process_id()); diff --git a/src/share/vm/runtime/reflectionUtils.cpp b/src/share/vm/runtime/reflectionUtils.cpp index 6c6e8c361..e8a986ab3 100644 --- a/src/share/vm/runtime/reflectionUtils.cpp +++ b/src/share/vm/runtime/reflectionUtils.cpp @@ -59,7 +59,7 @@ bool KlassStream::eos() { GrowableArray<FilteredField*> *FilteredFieldsMap::_filtered_fields = - new (ResourceObj::C_HEAP) GrowableArray<FilteredField*>(3,true); + new (ResourceObj::C_HEAP, mtInternal) GrowableArray<FilteredField*>(3,true); void FilteredFieldsMap::initialize() { diff --git a/src/share/vm/runtime/safepoint.cpp b/src/share/vm/runtime/safepoint.cpp index c29d257cc..31b33e320 100644 --- a/src/share/vm/runtime/safepoint.cpp +++ b/src/share/vm/runtime/safepoint.cpp @@ -48,6 +48,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/sweeper.hpp" #include "runtime/synchronizer.hpp" +#include "services/memTracker.hpp" #include "services/runtimeService.hpp" #include "utilities/events.hpp" #ifdef TARGET_ARCH_x86 @@ -546,6 +547,10 @@ void SafepointSynchronize::do_cleanup_tasks() { if (UseGCLogFileRotation) { gclog_or_tty->rotate_log(); } + + if (MemTracker::is_on()) { + MemTracker::sync(); + } } @@ -1157,7 +1162,7 @@ void SafepointSynchronize::deferred_initialize_stat() { stats_array_size = PrintSafepointStatisticsCount; } _safepoint_stats = (SafepointStats*)os::malloc(stats_array_size - * sizeof(SafepointStats)); + * sizeof(SafepointStats), mtInternal); guarantee(_safepoint_stats != NULL, "not enough memory for safepoint instrumentation data"); diff --git a/src/share/vm/runtime/safepoint.hpp b/src/share/vm/runtime/safepoint.hpp index 71255a27d..005ea4d03 100644 --- a/src/share/vm/runtime/safepoint.hpp +++ b/src/share/vm/runtime/safepoint.hpp @@ -190,7 +190,7 @@ public: }; // State class for a thread suspended at a safepoint -class ThreadSafepointState: public CHeapObj { +class ThreadSafepointState: public CHeapObj<mtInternal> { public: // These states are maintained by VM thread while threads are being brought // to a safepoint. After SafepointSynchronize::end(), they are reset to diff --git a/src/share/vm/runtime/sharedRuntime.cpp b/src/share/vm/runtime/sharedRuntime.cpp index 503ad0719..7c74f4930 100644 --- a/src/share/vm/runtime/sharedRuntime.cpp +++ b/src/share/vm/runtime/sharedRuntime.cpp @@ -2117,7 +2117,7 @@ void SharedRuntime::print_call_statistics(int comp_total) { // A simple wrapper class around the calling convention information // that allows sharing of adapters for the same calling convention. -class AdapterFingerPrint : public CHeapObj { +class AdapterFingerPrint : public CHeapObj<mtCode> { private: union { int _compact[3]; @@ -2174,7 +2174,7 @@ class AdapterFingerPrint : public CHeapObj { ptr = _value._compact; } else { _length = len; - _value._fingerprint = NEW_C_HEAP_ARRAY(int, _length); + _value._fingerprint = NEW_C_HEAP_ARRAY(int, _length, mtCode); ptr = _value._fingerprint; } @@ -2193,7 +2193,7 @@ class AdapterFingerPrint : public CHeapObj { ~AdapterFingerPrint() { if (_length > 0) { - FREE_C_HEAP_ARRAY(int, _value._fingerprint); + FREE_C_HEAP_ARRAY(int, _value._fingerprint, mtCode); } } @@ -2251,7 +2251,7 @@ class AdapterFingerPrint : public CHeapObj { // A hashtable mapping from AdapterFingerPrints to AdapterHandlerEntries -class AdapterHandlerTable : public BasicHashtable { +class AdapterHandlerTable : public BasicHashtable<mtCode> { friend class AdapterHandlerTableIterator; private: @@ -2265,16 +2265,16 @@ class AdapterHandlerTable : public BasicHashtable { #endif AdapterHandlerEntry* bucket(int i) { - return (AdapterHandlerEntry*)BasicHashtable::bucket(i); + return (AdapterHandlerEntry*)BasicHashtable<mtCode>::bucket(i); } public: AdapterHandlerTable() - : BasicHashtable(293, sizeof(AdapterHandlerEntry)) { } + : BasicHashtable<mtCode>(293, sizeof(AdapterHandlerEntry)) { } // Create a new entry suitable for insertion in the table AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry) { - AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable::new_entry(fingerprint->compute_hash()); + AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable<mtCode>::new_entry(fingerprint->compute_hash()); entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); return entry; } @@ -2287,7 +2287,7 @@ class AdapterHandlerTable : public BasicHashtable { void free_entry(AdapterHandlerEntry* entry) { entry->deallocate(); - BasicHashtable::free_entry(entry); + BasicHashtable<mtCode>::free_entry(entry); } // Find a entry with the same fingerprint if it exists @@ -2572,8 +2572,8 @@ void AdapterHandlerEntry::relocate(address new_base) { void AdapterHandlerEntry::deallocate() { delete _fingerprint; #ifdef ASSERT - if (_saved_code) FREE_C_HEAP_ARRAY(unsigned char, _saved_code); - if (_saved_sig) FREE_C_HEAP_ARRAY(Basictype, _saved_sig); + if (_saved_code) FREE_C_HEAP_ARRAY(unsigned char, _saved_code, mtCode); + if (_saved_sig) FREE_C_HEAP_ARRAY(Basictype, _saved_sig, mtCode); #endif } @@ -2583,11 +2583,11 @@ void AdapterHandlerEntry::deallocate() { // against other versions. If the code is captured after relocation // then relative instructions won't be equivalent. void AdapterHandlerEntry::save_code(unsigned char* buffer, int length, int total_args_passed, BasicType* sig_bt) { - _saved_code = NEW_C_HEAP_ARRAY(unsigned char, length); + _saved_code = NEW_C_HEAP_ARRAY(unsigned char, length, mtCode); _code_length = length; memcpy(_saved_code, buffer, length); _total_args_passed = total_args_passed; - _saved_sig = NEW_C_HEAP_ARRAY(BasicType, _total_args_passed); + _saved_sig = NEW_C_HEAP_ARRAY(BasicType, _total_args_passed, mtCode); memcpy(_saved_sig, sig_bt, _total_args_passed * sizeof(BasicType)); } @@ -2893,7 +2893,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) ) int max_locals = moop->max_locals(); // Allocate temp buffer, 1 word per local & 2 per active monitor int buf_size_words = max_locals + active_monitor_count*2; - intptr_t *buf = NEW_C_HEAP_ARRAY(intptr_t,buf_size_words); + intptr_t *buf = NEW_C_HEAP_ARRAY(intptr_t,buf_size_words, mtCode); // Copy the locals. Order is preserved so that loading of longs works. // Since there's no GC I can copy the oops blindly. @@ -2923,7 +2923,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *thread) ) JRT_END JRT_LEAF(void, SharedRuntime::OSR_migration_end( intptr_t* buf) ) - FREE_C_HEAP_ARRAY(intptr_t,buf); + FREE_C_HEAP_ARRAY(intptr_t,buf, mtCode); JRT_END bool AdapterHandlerLibrary::contains(CodeBlob* b) { diff --git a/src/share/vm/runtime/sharedRuntime.hpp b/src/share/vm/runtime/sharedRuntime.hpp index 9650c6e11..cb955c46d 100644 --- a/src/share/vm/runtime/sharedRuntime.hpp +++ b/src/share/vm/runtime/sharedRuntime.hpp @@ -610,7 +610,7 @@ class SharedRuntime: AllStatic { // used by the adapters. The code generation happens here because it's very // similar to what the adapters have to do. -class AdapterHandlerEntry : public BasicHashtableEntry { +class AdapterHandlerEntry : public BasicHashtableEntry<mtCode> { friend class AdapterHandlerTable; private: @@ -656,7 +656,7 @@ class AdapterHandlerEntry : public BasicHashtableEntry { AdapterFingerPrint* fingerprint() { return _fingerprint; } AdapterHandlerEntry* next() { - return (AdapterHandlerEntry*)BasicHashtableEntry::next(); + return (AdapterHandlerEntry*)BasicHashtableEntry<mtCode>::next(); } #ifdef ASSERT diff --git a/src/share/vm/runtime/stubCodeGenerator.hpp b/src/share/vm/runtime/stubCodeGenerator.hpp index bc81f5a30..3fb5161f8 100644 --- a/src/share/vm/runtime/stubCodeGenerator.hpp +++ b/src/share/vm/runtime/stubCodeGenerator.hpp @@ -36,7 +36,7 @@ // Currently, code descriptors are simply chained in a linked list, // this may have to change if searching becomes too slow. -class StubCodeDesc: public CHeapObj { +class StubCodeDesc: public CHeapObj<mtCode> { protected: static StubCodeDesc* _list; // the list of all descriptors static int _count; // length of list diff --git a/src/share/vm/runtime/sweeper.cpp b/src/share/vm/runtime/sweeper.cpp index 7f8561b6b..2dea6d7ba 100644 --- a/src/share/vm/runtime/sweeper.cpp +++ b/src/share/vm/runtime/sweeper.cpp @@ -228,7 +228,7 @@ void NMethodSweeper::possibly_sweep() { #ifdef ASSERT if (LogSweeper && _records == NULL) { // Create the ring buffer for the logging code - _records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries); + _records = NEW_C_HEAP_ARRAY(SweeperRecord, SweeperLogEntries, mtGC); memset(_records, 0, sizeof(SweeperRecord) * SweeperLogEntries); } #endif diff --git a/src/share/vm/runtime/task.hpp b/src/share/vm/runtime/task.hpp index 2357e835f..206442d76 100644 --- a/src/share/vm/runtime/task.hpp +++ b/src/share/vm/runtime/task.hpp @@ -35,7 +35,7 @@ // ... // pf.disenroll(); -class PeriodicTask: public CHeapObj { +class PeriodicTask: public CHeapObj<mtInternal> { public: // Useful constants. // The interval constants are used to ensure the declared interval diff --git a/src/share/vm/runtime/thread.cpp b/src/share/vm/runtime/thread.cpp index 76865f6ff..13f617db2 100644 --- a/src/share/vm/runtime/thread.cpp +++ b/src/share/vm/runtime/thread.cpp @@ -73,6 +73,7 @@ #include "runtime/vm_operations.hpp" #include "services/attachListener.hpp" #include "services/management.hpp" +#include "services/memTracker.hpp" #include "services/threadService.hpp" #include "trace/traceEventTypes.hpp" #include "utilities/defaultStream.hpp" @@ -159,6 +160,7 @@ HS_DTRACE_PROBE_DECL5(hotspot, thread__stop, char*, intptr_t, #endif // ndef DTRACE_ENABLED + // Class hierarchy // - Thread // - VMThread @@ -168,13 +170,13 @@ HS_DTRACE_PROBE_DECL5(hotspot, thread__stop, char*, intptr_t, // - CompilerThread // ======= Thread ======== - // Support for forcing alignment of thread objects for biased locking -void* Thread::operator new(size_t size) { +void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) { if (UseBiasedLocking) { const int alignment = markOopDesc::biased_lock_alignment; size_t aligned_size = size + (alignment - sizeof(intptr_t)); - void* real_malloc_addr = CHeapObj::operator new(aligned_size); + void* real_malloc_addr = throw_excpt? AllocateHeap(aligned_size, flags, CURRENT_PC) + : os::malloc(aligned_size, flags, CURRENT_PC); void* aligned_addr = (void*) align_size_up((intptr_t) real_malloc_addr, alignment); assert(((uintptr_t) aligned_addr + (uintptr_t) size) <= ((uintptr_t) real_malloc_addr + (uintptr_t) aligned_size), @@ -187,16 +189,17 @@ void* Thread::operator new(size_t size) { ((Thread*) aligned_addr)->_real_malloc_address = real_malloc_addr; return aligned_addr; } else { - return CHeapObj::operator new(size); + return throw_excpt? AllocateHeap(size, flags, CURRENT_PC) + : os::malloc(size, flags, CURRENT_PC); } } void Thread::operator delete(void* p) { if (UseBiasedLocking) { void* real_malloc_addr = ((Thread*) p)->_real_malloc_address; - CHeapObj::operator delete(real_malloc_addr); + FreeHeap(real_malloc_addr, mtThread); } else { - CHeapObj::operator delete(p); + FreeHeap(p, mtThread); } } @@ -214,8 +217,8 @@ Thread::Thread() { // allocated data structures set_osthread(NULL); - set_resource_area(new ResourceArea()); - set_handle_area(new HandleArea(NULL)); + set_resource_area(new (mtThread)ResourceArea()); + set_handle_area(new (mtThread) HandleArea(NULL)); set_active_handles(NULL); set_free_handle_block(NULL); set_last_handle_mark(NULL); @@ -306,12 +309,17 @@ void Thread::initialize_thread_local_storage() { // set up any platform-specific state. os::initialize_thread(); - } void Thread::record_stack_base_and_size() { set_stack_base(os::current_stack_base()); set_stack_size(os::current_stack_size()); + + // record thread's native stack, stack grows downward + address vm_base = _stack_base - _stack_size; + MemTracker::record_virtual_memory_reserve(vm_base, _stack_size, + CURRENT_PC, this); + MemTracker::record_virtual_memory_type(vm_base, mtThreadStack); } @@ -319,6 +327,9 @@ Thread::~Thread() { // Reclaim the objectmonitors from the omFreeList of the moribund thread. ObjectSynchronizer::omFlush (this) ; + MemTracker::record_virtual_memory_release((_stack_base - _stack_size), + _stack_size, this); + // deallocate data structures delete resource_area(); // since the handle marks are using the handle area, we have to deallocated the root @@ -1105,14 +1116,14 @@ NamedThread::NamedThread() : Thread() { NamedThread::~NamedThread() { if (_name != NULL) { - FREE_C_HEAP_ARRAY(char, _name); + FREE_C_HEAP_ARRAY(char, _name, mtThread); _name = NULL; } } void NamedThread::set_name(const char* format, ...) { guarantee(_name == NULL, "Only get to set name once."); - _name = NEW_C_HEAP_ARRAY(char, max_name_len); + _name = NEW_C_HEAP_ARRAY(char, max_name_len, mtThread); guarantee(_name != NULL, "alloc failure"); va_list ap; va_start(ap, format); @@ -1295,6 +1306,7 @@ void JavaThread::initialize() { set_monitor_chunks(NULL); set_next(NULL); set_thread_state(_thread_new); + set_recorder(NULL); _terminated = _not_terminated; _privileged_stack_top = NULL; _array_for_gc = NULL; @@ -1370,6 +1382,7 @@ JavaThread::JavaThread(bool is_attaching_via_jni) : _jni_attach_state = _not_attaching_via_jni; } assert(_deferred_card_mark.is_empty(), "Default MemRegion ctor"); + _safepoint_visible = false; } bool JavaThread::reguard_stack(address cur_sp) { @@ -1432,7 +1445,7 @@ JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) : thr_type = entry_point == &compiler_thread_entry ? os::compiler_thread : os::java_thread; os::create_thread(this, thr_type, stack_sz); - + _safepoint_visible = false; // The _osthread may be NULL here because we ran out of memory (too many threads active). // We need to throw and OutOfMemoryError - however we cannot do this here because the caller // may hold a lock and all locks must be unlocked before throwing the exception (throwing @@ -1450,6 +1463,11 @@ JavaThread::~JavaThread() { tty->print_cr("terminate thread %p", this); } + // Info NMT that this JavaThread is exiting, its memory + // recorder should be collected + assert(!is_safepoint_visible(), "wrong state"); + MemTracker::thread_exiting(this); + // JSR166 -- return the parker to the free list Parker::Release(_parker); _parker = NULL ; @@ -2892,7 +2910,7 @@ void JavaThread::print_stack_on(outputStream* st) { void JavaThread::popframe_preserve_args(ByteSize size_in_bytes, void* start) { assert(_popframe_preserved_args == NULL, "should not wipe out old PopFrame preserved arguments"); if (in_bytes(size_in_bytes) != 0) { - _popframe_preserved_args = NEW_C_HEAP_ARRAY(char, in_bytes(size_in_bytes)); + _popframe_preserved_args = NEW_C_HEAP_ARRAY(char, in_bytes(size_in_bytes), mtThread); _popframe_preserved_args_size = in_bytes(size_in_bytes); Copy::conjoint_jbytes(start, _popframe_preserved_args, _popframe_preserved_args_size); } @@ -2914,7 +2932,7 @@ WordSize JavaThread::popframe_preserved_args_size_in_words() { void JavaThread::popframe_free_preserved_args() { assert(_popframe_preserved_args != NULL, "should not free PopFrame preserved arguments twice"); - FREE_C_HEAP_ARRAY(char, (char*) _popframe_preserved_args); + FREE_C_HEAP_ARRAY(char, (char*) _popframe_preserved_args, mtThread); _popframe_preserved_args = NULL; _popframe_preserved_args_size = 0; } @@ -3163,6 +3181,14 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { jint os_init_2_result = os::init_2(); if (os_init_2_result != JNI_OK) return os_init_2_result; + // intialize TLS + ThreadLocalStorage::init(); + + // Bootstrap native memory tracking, so it can start recording memory + // activities before worker thread is started. This is the first phase + // of bootstrapping, VM is currently running in single-thread mode. + MemTracker::bootstrap_single_thread(); + // Initialize output stream logging ostream_init_log(); @@ -3182,9 +3208,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { _number_of_threads = 0; _number_of_non_daemon_threads = 0; - // Initialize TLS - ThreadLocalStorage::init(); - // Initialize global data structures and create system classes in heap vm_init_globals(); @@ -3216,6 +3239,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Initialize Java-Level synchronization subsystem ObjectMonitor::Initialize() ; + // Second phase of bootstrapping, VM is about entering multi-thread mode + MemTracker::bootstrap_multi_thread(); + // Initialize global modules jint status = init_globals(); if (status != JNI_OK) { @@ -3243,6 +3269,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { Universe::verify(); // make sure we're starting with a clean slate } + // Fully start NMT + MemTracker::start(); + // Create the VMThread { TraceTime timer("Start VMThread", TraceStartupTime); VMThread::create(); @@ -3544,11 +3573,11 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym if (library == NULL) { const char *sub_msg = " in absolute path, with error: "; size_t len = strlen(msg) + strlen(name) + strlen(sub_msg) + strlen(ebuf) + 1; - char *buf = NEW_C_HEAP_ARRAY(char, len); + char *buf = NEW_C_HEAP_ARRAY(char, len, mtThread); jio_snprintf(buf, len, "%s%s%s%s", msg, name, sub_msg, ebuf); // If we can't find the agent, exit. vm_exit_during_initialization(buf, NULL); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(char, buf, mtThread); } } else { // Try to load the agent from the standard dll directory @@ -3562,7 +3591,7 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym const char *fmt = "%s/bin/java %s -Dkernel.background.download=false" " sun.jkernel.DownloadManager -download client_jvm"; size_t length = strlen(props) + strlen(home) + strlen(fmt) + 1; - char *cmd = NEW_C_HEAP_ARRAY(char, length); + char *cmd = NEW_C_HEAP_ARRAY(char, length, mtThread); jio_snprintf(cmd, length, fmt, home, props); int status = os::fork_and_exec(cmd); FreeHeap(props); @@ -3571,7 +3600,7 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym vm_exit_during_initialization("fork_and_exec failed: %s", strerror(errno)); } - FREE_C_HEAP_ARRAY(char, cmd); + FREE_C_HEAP_ARRAY(char, cmd, mtThread); // when this comes back the instrument.dll should be where it belongs. library = os::dll_load(buffer, ebuf, sizeof ebuf); } @@ -3583,11 +3612,11 @@ static OnLoadEntry_t lookup_on_load(AgentLibrary* agent, const char *on_load_sym if (library == NULL) { const char *sub_msg = " on the library path, with error: "; size_t len = strlen(msg) + strlen(name) + strlen(sub_msg) + strlen(ebuf) + 1; - char *buf = NEW_C_HEAP_ARRAY(char, len); + char *buf = NEW_C_HEAP_ARRAY(char, len, mtThread); jio_snprintf(buf, len, "%s%s%s%s", msg, name, sub_msg, ebuf); // If we can't find the agent, exit. vm_exit_during_initialization(buf, NULL); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(char, buf, mtThread); } } } @@ -3756,6 +3785,7 @@ void JavaThread::invoke_shutdown_hooks() { // and VM_Exit op at VM level. // // Shutdown sequence: +// + Shutdown native memory tracking if it is on // + Wait until we are the last non-daemon thread to execute // <-- every thing is still working at this moment --> // + Call java.lang.Shutdown.shutdown(), which will invoke Java level @@ -3801,6 +3831,10 @@ bool Threads::destroy_vm() { Mutex::_as_suspend_equivalent_flag); } + // Shutdown NMT before exit. Otherwise, + // it will run into trouble when system destroys static variables. + MemTracker::shutdown(MemTracker::NMT_normal); + // Hang forever on exit if we are reporting an error. if (ShowMessageBoxOnError && is_error_reported()) { os::infinite_sleep(); @@ -3907,6 +3941,8 @@ void Threads::add(JavaThread* p, bool force_daemon) { daemon = false; } + p->set_safepoint_visible(true); + ThreadService::add_thread(p, daemon); // Possible GC point. @@ -3952,6 +3988,10 @@ void Threads::remove(JavaThread* p) { // to do callbacks into the safepoint code. However, the safepoint code is not aware // of this thread since it is removed from the queue. p->set_terminated_value(); + + // Now, this thread is not visible to safepoint + p->set_safepoint_visible(false); + } // unlock Threads_lock // Since Events::log uses a lock, we grab it outside the Threads_lock diff --git a/src/share/vm/runtime/thread.hpp b/src/share/vm/runtime/thread.hpp index 7846cc070..a375f264f 100644 --- a/src/share/vm/runtime/thread.hpp +++ b/src/share/vm/runtime/thread.hpp @@ -41,6 +41,7 @@ #include "runtime/stubRoutines.hpp" #include "runtime/threadLocalStorage.hpp" #include "runtime/unhandledOops.hpp" +#include "services/memRecorder.hpp" #include "trace/tracing.hpp" #include "utilities/exceptions.hpp" #include "utilities/top.hpp" @@ -100,12 +101,16 @@ class Thread: public ThreadShadow { //oop _pending_exception; // pending exception for current thread // const char* _exception_file; // file information for exception (debugging only) // int _exception_line; // line information for exception (debugging only) - + protected: // Support for forcing alignment of thread objects for biased locking void* _real_malloc_address; public: - void* operator new(size_t size); + void* operator new(size_t size) { return allocate(size, true); } + void* operator new(size_t size, std::nothrow_t& nothrow_constant) { return allocate(size, false); } void operator delete(void* p); + + protected: + static void* allocate(size_t size, bool throw_excpt, MEMFLAGS flags = mtThread); private: // *************************************************************** @@ -548,7 +553,6 @@ public: virtual void print_on_error(outputStream* st, char* buf, int buflen) const; // Debug-only code - #ifdef ASSERT private: // Deadlock detection support for Mutex locks. List of locks own by thread. @@ -1027,9 +1031,15 @@ class JavaThread: public Thread { bool do_not_unlock_if_synchronized() { return _do_not_unlock_if_synchronized; } void set_do_not_unlock_if_synchronized(bool val) { _do_not_unlock_if_synchronized = val; } + // native memory tracking + inline MemRecorder* get_recorder() const { return (MemRecorder*)_recorder; } + inline void set_recorder(MemRecorder* rc) { _recorder = (volatile MemRecorder*)rc; } - // Suspend/resume support for JavaThread + private: + // per-thread memory recorder + volatile MemRecorder* _recorder; + // Suspend/resume support for JavaThread private: void set_ext_suspended() { set_suspend_flag (_ext_suspended); } void clear_ext_suspended() { clear_suspend_flag(_ext_suspended); } @@ -1453,6 +1463,18 @@ public: return result; } + // NMT (Native memory tracking) support. + // This flag helps NMT to determine if this JavaThread will be blocked + // at safepoint. If not, ThreadCritical is needed for writing memory records. + // JavaThread is only safepoint visible when it is in Threads' thread list, + // it is not visible until it is added to the list and becomes invisible + // once it is removed from the list. + public: + bool is_safepoint_visible() const { return _safepoint_visible; } + void set_safepoint_visible(bool visible) { _safepoint_visible = visible; } + private: + bool _safepoint_visible; + // Static operations public: // Returns the running thread as a JavaThread diff --git a/src/share/vm/runtime/unhandledOops.cpp b/src/share/vm/runtime/unhandledOops.cpp index 9b7211c8d..3216da1f2 100644 --- a/src/share/vm/runtime/unhandledOops.cpp +++ b/src/share/vm/runtime/unhandledOops.cpp @@ -37,7 +37,7 @@ const int free_list_size = 256; UnhandledOops::UnhandledOops(Thread* thread) { _thread = thread; - _oop_list = new (ResourceObj::C_HEAP) + _oop_list = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<UnhandledOopEntry>(free_list_size, true); _level = 0; } diff --git a/src/share/vm/runtime/vframeArray.cpp b/src/share/vm/runtime/vframeArray.cpp index 52b080999..742197394 100644 --- a/src/share/vm/runtime/vframeArray.cpp +++ b/src/share/vm/runtime/vframeArray.cpp @@ -443,7 +443,7 @@ vframeArray* vframeArray::allocate(JavaThread* thread, int frame_size, GrowableA // Allocate the vframeArray vframeArray * result = (vframeArray*) AllocateHeap(sizeof(vframeArray) + // fixed part sizeof(vframeArrayElement) * (chunk->length() - 1), // variable part - "vframeArray::allocate"); + mtCompiler); result->_frames = chunk->length(); result->_owner_thread = thread; result->_sender = sender; diff --git a/src/share/vm/runtime/vframeArray.hpp b/src/share/vm/runtime/vframeArray.hpp index 6f8d436c6..2eeeb39e6 100644 --- a/src/share/vm/runtime/vframeArray.hpp +++ b/src/share/vm/runtime/vframeArray.hpp @@ -108,7 +108,7 @@ class vframeArrayElement : public _ValueObj { // but it does make debugging easier even if we can't look // at the data in each vframeElement -class vframeArray: public CHeapObj { +class vframeArray: public CHeapObj<mtCompiler> { friend class VMStructs; private: diff --git a/src/share/vm/runtime/vframe_hp.cpp b/src/share/vm/runtime/vframe_hp.cpp index 274bfc604..4f63575d9 100644 --- a/src/share/vm/runtime/vframe_hp.cpp +++ b/src/share/vm/runtime/vframe_hp.cpp @@ -154,7 +154,7 @@ void compiledVFrame::update_local(BasicType type, int index, jvalue value) { } else { // No deferred updates pending for this thread. // allocate in C heap - deferred = new(ResourceObj::C_HEAP) GrowableArray<jvmtiDeferredLocalVariableSet*> (1, true); + deferred = new(ResourceObj::C_HEAP, mtCompiler) GrowableArray<jvmtiDeferredLocalVariableSet*> (1, true); thread()->set_deferred_locals(deferred); } deferred->push(new jvmtiDeferredLocalVariableSet(method(), bci(), fr().id())); @@ -323,7 +323,7 @@ jvmtiDeferredLocalVariableSet::jvmtiDeferredLocalVariableSet(methodOop method, i _bci = bci; _id = id; // Alway will need at least one, must be on C heap - _locals = new(ResourceObj::C_HEAP) GrowableArray<jvmtiDeferredLocalVariable*> (1, true); + _locals = new(ResourceObj::C_HEAP, mtCompiler) GrowableArray<jvmtiDeferredLocalVariable*> (1, true); } jvmtiDeferredLocalVariableSet::~jvmtiDeferredLocalVariableSet() { diff --git a/src/share/vm/runtime/vframe_hp.hpp b/src/share/vm/runtime/vframe_hp.hpp index 6d0bd3764..4edb53bc8 100644 --- a/src/share/vm/runtime/vframe_hp.hpp +++ b/src/share/vm/runtime/vframe_hp.hpp @@ -89,7 +89,7 @@ class compiledVFrame: public javaVFrame { // any updated locals. class jvmtiDeferredLocalVariable; -class jvmtiDeferredLocalVariableSet : public CHeapObj { +class jvmtiDeferredLocalVariableSet : public CHeapObj<mtCompiler> { private: methodOop _method; // must be GC'd @@ -119,7 +119,7 @@ private: }; -class jvmtiDeferredLocalVariable : public CHeapObj { +class jvmtiDeferredLocalVariable : public CHeapObj<mtCompiler> { public: jvmtiDeferredLocalVariable(int index, BasicType type, jvalue value); diff --git a/src/share/vm/runtime/virtualspace.cpp b/src/share/vm/runtime/virtualspace.cpp index c7e6bf80f..38f434dce 100644 --- a/src/share/vm/runtime/virtualspace.cpp +++ b/src/share/vm/runtime/virtualspace.cpp @@ -26,6 +26,7 @@ #include "oops/markOop.hpp" #include "oops/oop.inline.hpp" #include "runtime/virtualspace.hpp" +#include "services/memTracker.hpp" #ifdef TARGET_OS_FAMILY_linux # include "os_linux.inline.hpp" #endif @@ -489,6 +490,10 @@ ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), alignment) : 0) { + if (base() > 0) { + MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); + } + // Only reserved space for the java heap should have a noaccess_prefix // if using compressed oops. protect_noaccess_prefix(size); @@ -504,6 +509,10 @@ ReservedHeapSpace::ReservedHeapSpace(const size_t prefix_size, (UseCompressedOops && (Universe::narrow_oop_base() != NULL) && Universe::narrow_oop_use_implicit_null_checks()) ? lcm(os::vm_page_size(), prefix_align) : 0) { + if (base() > 0) { + MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap); + } + protect_noaccess_prefix(prefix_size+suffix_size); } @@ -513,6 +522,7 @@ ReservedCodeSpace::ReservedCodeSpace(size_t r_size, size_t rs_align, bool large) : ReservedSpace(r_size, rs_align, large, /*executable*/ true) { + MemTracker::record_virtual_memory_type((address)base(), mtCode); } // VirtualSpace diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp index 7045fa8b3..57fab3369 100644 --- a/src/share/vm/runtime/vmStructs.cpp +++ b/src/share/vm/runtime/vmStructs.cpp @@ -235,7 +235,6 @@ #ifndef REG_COUNT #define REG_COUNT 0 #endif - // whole purpose of this function is to work around bug c++/27724 in gcc 4.1.1 // with optimization turned on it doesn't affect produced code static inline uint64_t cast_uint64_t(size_t x) @@ -244,6 +243,16 @@ static inline uint64_t cast_uint64_t(size_t x) } +typedef HashtableEntry<intptr_t, mtInternal> IntptrHashtableEntry; +typedef Hashtable<intptr_t, mtInternal> IntptrHashtable; +typedef Hashtable<Symbol*, mtSymbol> SymbolHashtable; +typedef HashtableEntry<Symbol*, mtClass> SymbolHashtableEntry; +typedef Hashtable<oop, mtSymbol> StringHashtable; +typedef TwoOopHashtable<klassOop, mtClass> klassOopTwoOopHashtable; +typedef Hashtable<klassOop, mtClass> klassOopHashtable; +typedef HashtableEntry<klassOop, mtClass> klassHashtableEntry; +typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; + //-------------------------------------------------------------------------------- // VM_STRUCTS // @@ -711,26 +720,26 @@ static inline uint64_t cast_uint64_t(size_t x) /* HashtableBucket */ \ /*******************/ \ \ - nonstatic_field(HashtableBucket, _entry, BasicHashtableEntry*) \ + nonstatic_field(HashtableBucket<mtInternal>, _entry, BasicHashtableEntry<mtInternal>*) \ \ /******************/ \ /* HashtableEntry */ \ /******************/ \ \ - nonstatic_field(BasicHashtableEntry, _next, BasicHashtableEntry*) \ - nonstatic_field(BasicHashtableEntry, _hash, unsigned int) \ - nonstatic_field(HashtableEntry<intptr_t>, _literal, intptr_t) \ + nonstatic_field(BasicHashtableEntry<mtInternal>, _next, BasicHashtableEntry<mtInternal>*) \ + nonstatic_field(BasicHashtableEntry<mtInternal>, _hash, unsigned int) \ + nonstatic_field(IntptrHashtableEntry, _literal, intptr_t) \ \ /*************/ \ /* Hashtable */ \ /*************/ \ \ - nonstatic_field(BasicHashtable, _table_size, int) \ - nonstatic_field(BasicHashtable, _buckets, HashtableBucket*) \ - nonstatic_field(BasicHashtable, _free_list, BasicHashtableEntry*) \ - nonstatic_field(BasicHashtable, _first_free_entry, char*) \ - nonstatic_field(BasicHashtable, _end_block, char*) \ - nonstatic_field(BasicHashtable, _entry_size, int) \ + nonstatic_field(BasicHashtable<mtInternal>, _table_size, int) \ + nonstatic_field(BasicHashtable<mtInternal>, _buckets, HashtableBucket<mtInternal>*) \ + nonstatic_field(BasicHashtable<mtInternal>, _free_list, BasicHashtableEntry<mtInternal>*) \ + nonstatic_field(BasicHashtable<mtInternal>, _first_free_entry, char*) \ + nonstatic_field(BasicHashtable<mtInternal>, _end_block, char*) \ + nonstatic_field(BasicHashtable<mtInternal>, _entry_size, int) \ \ /*******************/ \ /* DictionaryEntry */ \ @@ -1538,20 +1547,20 @@ static inline uint64_t cast_uint64_t(size_t x) /* SymbolTable, SystemDictionary */ \ /*********************************/ \ \ - declare_toplevel_type(BasicHashtable) \ - declare_type(Hashtable<intptr_t>, BasicHashtable) \ - declare_type(SymbolTable, Hashtable<Symbol*>) \ - declare_type(StringTable, Hashtable<oop>) \ - declare_type(LoaderConstraintTable, Hashtable<klassOop>) \ - declare_type(TwoOopHashtable<klassOop>, Hashtable<klassOop>) \ - declare_type(Dictionary, TwoOopHashtable<klassOop>) \ - declare_type(PlaceholderTable, TwoOopHashtable<Symbol*>) \ - declare_toplevel_type(BasicHashtableEntry) \ - declare_type(HashtableEntry<intptr_t>, BasicHashtableEntry) \ - declare_type(DictionaryEntry, HashtableEntry<klassOop>) \ - declare_type(PlaceholderEntry, HashtableEntry<Symbol*>) \ - declare_type(LoaderConstraintEntry, HashtableEntry<klassOop>) \ - declare_toplevel_type(HashtableBucket) \ + declare_toplevel_type(BasicHashtable<mtInternal>) \ + declare_type(IntptrHashtable, BasicHashtable<mtInternal>) \ + declare_type(SymbolTable, SymbolHashtable) \ + declare_type(StringTable, StringHashtable) \ + declare_type(LoaderConstraintTable, klassOopHashtable) \ + declare_type(klassOopTwoOopHashtable, klassOopHashtable) \ + declare_type(Dictionary, klassOopTwoOopHashtable) \ + declare_type(PlaceholderTable, SymbolTwoOopHashtable) \ + declare_toplevel_type(BasicHashtableEntry<mtInternal>) \ + declare_type(IntptrHashtableEntry, BasicHashtableEntry<mtInternal>) \ + declare_type(DictionaryEntry, klassHashtableEntry) \ + declare_type(PlaceholderEntry, SymbolHashtableEntry) \ + declare_type(LoaderConstraintEntry, klassHashtableEntry) \ + declare_toplevel_type(HashtableBucket<mtInternal>) \ declare_toplevel_type(SystemDictionary) \ declare_toplevel_type(vmSymbols) \ declare_toplevel_type(ProtectionDomainEntry) \ diff --git a/src/share/vm/runtime/vmThread.hpp b/src/share/vm/runtime/vmThread.hpp index f78449676..acf95842b 100644 --- a/src/share/vm/runtime/vmThread.hpp +++ b/src/share/vm/runtime/vmThread.hpp @@ -46,7 +46,7 @@ // Encapsulates both queue management and // and priority policy // -class VMOperationQueue : public CHeapObj { +class VMOperationQueue : public CHeapObj<mtInternal> { private: enum Priorities { SafepointPriority, // Highest priority (operation executed at a safepoint) diff --git a/src/share/vm/runtime/vm_operations.hpp b/src/share/vm/runtime/vm_operations.hpp index 081c428a6..ccbad94b7 100644 --- a/src/share/vm/runtime/vm_operations.hpp +++ b/src/share/vm/runtime/vm_operations.hpp @@ -96,7 +96,7 @@ template(JFRCheckpoint) \ template(Exit) \ -class VM_Operation: public CHeapObj { +class VM_Operation: public CHeapObj<mtInternal> { public: enum Mode { _safepoint, // blocking, safepoint, vm_op C-heap allocated |