--- old/src/share/vm/memory/allocation.cpp 2015-02-09 11:39:11.363857000 -0500 +++ new/src/share/vm/memory/allocation.cpp 2015-02-09 11:39:11.050088000 -0500 @@ -275,31 +275,30 @@ Chunk* cur = NULL; Chunk* next; { - // if we have more than n chunks, free all of them - ThreadCritical tc; - if (_num_chunks > n) { - // free chunks at end of queue, for better locality + // if we have more than n chunks, free all of them + ThreadCritical tc; + if (_num_chunks > n) { + // free chunks at end of queue, for better locality cur = _first; - for (size_t i = 0; i < (n - 1) && cur != NULL; i++) cur = cur->next(); + for (size_t i = 0; i < (n - 1) && cur != NULL; i++) cur = cur->next(); - if (cur != NULL) { + if (cur != NULL) { next = cur->next(); - cur->set_next(NULL); - cur = next; + cur->set_next(NULL); + cur = next; - _num_chunks = n; + // Free all remaining chunks while in ThreadCritical lock + // so NMT adjustment is stable. + while(cur != NULL) { + next = cur->next(); + os::free(cur); + _num_chunks--; + cur = next; + } } } } - - // Free all remaining chunks, outside of ThreadCritical - // to avoid deadlock with NMT - while(cur != NULL) { - next = cur->next(); - os::free(cur); - cur = next; - } - } + } // Accessors to preallocated pool's static ChunkPool* large_pool() { assert(_large_pool != NULL, "must be initialized"); return _large_pool; } @@ -384,7 +383,9 @@ case Chunk::medium_size: ChunkPool::medium_pool()->free(c); break; case Chunk::init_size: ChunkPool::small_pool()->free(c); break; case Chunk::tiny_size: ChunkPool::tiny_pool()->free(c); break; - default: os::free(c); + default: + ThreadCritical tc; // Free chunks under TC lock so that NMT adjustment is stable. + os::free(c); } } --- old/src/share/vm/services/mallocTracker.hpp 2015-02-09 11:39:11.474842000 -0500 +++ new/src/share/vm/services/mallocTracker.hpp 2015-02-09 11:39:11.062921000 -0500 @@ -164,6 +164,10 @@ } void copy_to(MallocMemorySnapshot* s) { + // Need to make sure that mtChunks don't get deallocated while the + // copy is going on, because their size is adjusted using this + // buffer in make_adjustment(). + ThreadCritical tc; s->_tracking_header = _tracking_header; for (int index = 0; index < mt_number_of_types; index ++) { s->_malloc[index] = _malloc[index]; --- old/src/share/vm/services/mallocSiteTable.cpp 2015-02-09 11:39:11.491616000 -0500 +++ new/src/share/vm/services/mallocSiteTable.cpp 2015-02-09 11:39:11.077035000 -0500 @@ -136,7 +136,7 @@ MallocSite* MallocSiteTable::lookup_or_add(const NativeCallStack& key, size_t* bucket_idx, size_t* pos_idx) { int index = hash_to_index(key.hash()); - assert(index >= 0, "Negative index"); + assert(index >= 0, err_msg("Negative index %d", index)); *bucket_idx = (size_t)index; *pos_idx = 0; --- old/src/share/vm/services/nmtDCmd.cpp 2015-02-09 11:39:11.493013000 -0500 +++ new/src/share/vm/services/nmtDCmd.cpp 2015-02-09 11:39:11.098774000 -0500 @@ -137,8 +137,8 @@ } } else if (_detail_diff.value()) { if (!check_detail_tracking_level(output())) { - return; - } + return; + } MemBaseline& baseline = MemTracker::get_baseline(); if (baseline.baseline_type() == MemBaseline::Detail_baselined) { report_diff(false, scale_unit); --- old/src/share/vm/services/mallocTracker.cpp 2015-02-09 11:39:11.463021000 -0500 +++ new/src/share/vm/services/mallocTracker.cpp 2015-02-09 11:39:11.086975000 -0500 @@ -52,7 +52,7 @@ } // Make adjustment by subtracting chunks used by arenas -// from total chunks to get total free chunck size +// from total chunks to get total free chunk size void MallocMemorySnapshot::make_adjustment() { size_t arena_size = total_arena(); int chunk_idx = NMTUtil::flag_to_index(mtChunk);