28
#include "precompiled.hpp"
30
#include "logging/log.hpp"
31
#include "logging/logStream.hpp"
32
#include "nmt/mallocHeader.inline.hpp"
33
#include "nmt/mallocLimit.hpp"
34
#include "nmt/mallocSiteTable.hpp"
35
#include "nmt/mallocTracker.hpp"
36
#include "nmt/memTracker.hpp"
37
#include "runtime/arguments.hpp"
38
#include "runtime/atomic.hpp"
39
#include "runtime/globals.hpp"
40
#include "runtime/os.hpp"
41
#include "runtime/safefetch.hpp"
42
#include "utilities/debug.hpp"
43
#include "utilities/macros.hpp"
44
#include "utilities/ostream.hpp"
45
#include "utilities/vmError.hpp"
46
#include "utilities/globalDefinitions.hpp"
48
MallocMemorySnapshot MallocMemorySummary::_snapshot;
50
void MemoryCounter::update_peak(size_t size, size_t cnt) {
51
size_t peak_sz = peak_size();
52
while (peak_sz < size) {
53
size_t old_sz = Atomic::cmpxchg(&_peak_size, peak_sz, size, memory_order_relaxed);
54
if (old_sz == peak_sz) {
64
void MallocMemorySnapshot::copy_to(MallocMemorySnapshot* s) {
69
s->_all_mallocs = _all_mallocs;
70
size_t total_size = 0;
71
size_t total_count = 0;
72
for (int index = 0; index < mt_number_of_types; index ++) {
73
s->_malloc[index] = _malloc[index];
74
total_size += s->_malloc[index].malloc_size();
75
total_count += s->_malloc[index].malloc_count();
78
s->_all_mallocs.set_size_and_count(total_size, total_count);
82
size_t MallocMemorySnapshot::total_arena() const {
84
for (int index = 0; index < mt_number_of_types; index ++) {
85
amount += _malloc[index].arena_size();
92
void MallocMemorySnapshot::make_adjustment() {
93
size_t arena_size = total_arena();
94
int chunk_idx = NMTUtil::flag_to_index(mtChunk);
95
_malloc[chunk_idx].record_free(arena_size);
96
_all_mallocs.deallocate(arena_size);
99
void MallocMemorySummary::initialize() {
101
MallocLimitHandler::initialize(MallocLimit);
104
bool MallocMemorySummary::total_limit_reached(size_t s, size_t so_far, const malloclimit* limit) {
107
"MallocLimit: reached global limit (triggering allocation size: " PROPERFMT ", allocated so far: " PROPERFMT ", limit: " PROPERFMT ") ", \
108
PROPERFMTARGS(s), PROPERFMTARGS(so_far), PROPERFMTARGS(limit->sz)
112
if (VMError::is_error_reported()) {
114
static int stopafter = 10;
115
if (stopafter-- > 0) {
116
log_warning(nmt)(FORMATTED);
121
if (limit->mode == MallocLimitMode::trigger_fatal) {
124
log_warning(nmt)(FORMATTED);
131
bool MallocMemorySummary::category_limit_reached(MEMFLAGS f, size_t s, size_t so_far, const malloclimit* limit) {
134
"MallocLimit: reached category \"%s\" limit (triggering allocation size: " PROPERFMT ", allocated so far: " PROPERFMT ", limit: " PROPERFMT ") ", \
135
NMTUtil::flag_to_enum_name(f), PROPERFMTARGS(s), PROPERFMTARGS(so_far), PROPERFMTARGS(limit->sz)
139
if (VMError::is_error_reported()) {
141
static int stopafter = 10;
142
if (stopafter-- > 0) {
143
log_warning(nmt)(FORMATTED);
148
if (limit->mode == MallocLimitMode::trigger_fatal) {
151
log_warning(nmt)(FORMATTED);
158
bool MallocTracker::initialize(NMT_TrackingLevel level) {
159
if (level >= NMT_summary) {
160
MallocMemorySummary::initialize();
163
if (level == NMT_detail) {
164
return MallocSiteTable::initialize();
170
void* MallocTracker::record_malloc(void* malloc_base, size_t size, MEMFLAGS flags,
171
const NativeCallStack& stack)
173
assert(MemTracker::enabled(), "precondition");
174
assert(malloc_base != nullptr, "precondition");
176
MallocMemorySummary::record_malloc(size, flags);
177
uint32_t mst_marker = 0;
178
if (MemTracker::tracking_level() == NMT_detail) {
179
MallocSiteTable::allocation_at(stack, size, &mst_marker, flags);
183
MallocHeader* const header = ::new (malloc_base)MallocHeader(size, flags, mst_marker);
184
void* const memblock = (void*)((char*)malloc_base + sizeof(MallocHeader));
188
assert(((size_t)memblock & (sizeof(size_t) * 2 - 1)) == 0, "Alignment check");
193
const MallocHeader* header2 = MallocHeader::resolve_checked(memblock);
194
assert(header2->size() == size, "Wrong size");
195
assert(header2->flags() == flags, "Wrong flags");
202
void* MallocTracker::record_free_block(void* memblock) {
203
assert(MemTracker::enabled(), "Sanity");
204
assert(memblock != nullptr, "precondition");
206
MallocHeader* header = MallocHeader::resolve_checked(memblock);
208
deaccount(header->free_info());
210
header->mark_block_as_dead();
212
return (void*)header;
215
void MallocTracker::deaccount(MallocHeader::FreeInfo free_info) {
216
MallocMemorySummary::record_free(free_info.size, free_info.flags);
217
if (MemTracker::tracking_level() == NMT_detail) {
218
MallocSiteTable::deallocation_at(free_info.size, free_info.mst_marker);
227
bool MallocTracker::print_pointer_information(const void* p, outputStream* st) {
228
assert(MemTracker::enabled(), "NMT not enabled");
232
address addr = (address)p;
238
const MallocHeader* likely_dead_block = nullptr;
239
const MallocHeader* likely_live_block = nullptr;
241
const size_t smallest_possible_alignment = sizeof(void*);
242
const uint8_t* here = align_down(addr, smallest_possible_alignment);
243
const uint8_t* const end = here - (0x1000 + sizeof(MallocHeader));
244
for (; here >= end; here -= smallest_possible_alignment) {
246
if (!os::is_readable_range(here, here + sizeof(MallocHeader))) {
250
const MallocHeader* const candidate = (const MallocHeader*)here;
251
if (!candidate->looks_valid()) {
261
const address start_block = (address)candidate;
262
const address start_payload = (address)(candidate + 1);
263
const address end_payload = start_payload + candidate->size();
264
const address end_payload_plus_fudge = end_payload + fudge;
265
if (addr >= start_block && addr < end_payload_plus_fudge) {
270
if (candidate->is_live()) {
271
likely_live_block = candidate;
274
likely_dead_block = candidate;
282
const MallocHeader* block = likely_live_block != nullptr ? likely_live_block : likely_dead_block;
283
if (block != nullptr) {
284
const char* where = nullptr;
285
const address start_block = (address)block;
286
const address start_payload = (address)(block + 1);
287
const address end_payload = start_payload + block->size();
288
if (addr < start_payload) {
289
where = "into header of";
290
} else if (addr < end_payload) {
293
where = "just outside of";
295
st->print_cr(PTR_FORMAT " %s %s malloced block starting at " PTR_FORMAT ", size " SIZE_FORMAT ", tag %s",
297
(block->is_dead() ? "dead" : "live"),
299
block->size(), NMTUtil::flag_to_enum_name(block->flags()));
300
if (MemTracker::tracking_level() == NMT_detail) {
302
if (MallocSiteTable::access_stack(ncs, *block)) {