< prev index next >
src/hotspot/share/runtime/heapMonitoring.cpp
Print this page
rev 48551 : [mq]: heap8
rev 48552 : [mq]: heap10a
rev 48553 : [mq]: heap14_rebased
rev 48555 : [mq]: heap16
rev 48556 : [mq]: heap17
rev 48557 : [mq]: heap17
@@ -29,33 +29,43 @@
#include "runtime/heapMonitoring.hpp"
#include "runtime/vframe.hpp"
static const int MaxStackDepth = 1024;
-// Internal data structure representing traces.
+// Internal data structure representing traces, used when object has been GC'd.
struct StackTraceData : CHeapObj<mtInternal> {
- jvmtiStackTrace *trace;
- oop obj;
+ jvmtiStackTrace* trace;
int references;
- StackTraceData(jvmtiStackTrace *t, oop o) : trace(t), obj(o), references(0) {}
+ StackTraceData(jvmtiStackTrace* t) : trace(t), references(0) {}
- StackTraceData() : trace(NULL), obj(NULL), references(0) {}
+ StackTraceData() : trace(NULL), references(0) {}
// StackTraceDatas are shared around the board between various lists. So
// handle this by hand instead of having this in the destructor. There are
// cases where the struct is on the stack but holding heap data not to be
// freed.
- static void free_data(StackTraceData *data) {
+ static void free_data(StackTraceData* data) {
if (data->trace != NULL) {
FREE_C_HEAP_ARRAY(jvmtiFrameInfo, data->trace->frames);
FREE_C_HEAP_OBJ(data->trace);
}
delete data;
}
};
+// Internal data structure representing traces with the oop, used while object
+// is live. Since this structure just passes the trace to the GC lists, it does
+// not handle any freeing.
+struct StackTraceDataWithOop : public StackTraceData {
+ oop obj;
+
+ StackTraceDataWithOop(jvmtiStackTrace* t, oop o) : StackTraceData(t), obj(o) {}
+
+ StackTraceDataWithOop() : StackTraceData(), obj(NULL) {}
+};
+
// Fixed size buffer for holding garbage traces.
class GarbageTracesBuffer : public CHeapObj<mtInternal> {
public:
GarbageTracesBuffer(uint32_t size) : _size(size) {
_garbage_traces = NEW_C_HEAP_ARRAY(StackTraceData*,
@@ -70,17 +80,17 @@
StackTraceData** get_traces() const {
return _garbage_traces;
}
- bool store_trace(StackTraceData *trace) {
+ bool store_trace(StackTraceData* trace) {
uint32_t index;
if (!select_replacement(&index)) {
return false;
}
- StackTraceData *old_data = _garbage_traces[index];
+ StackTraceData* old_data = _garbage_traces[index];
if (old_data != NULL) {
old_data->references--;
if (old_data->references == 0) {
@@ -99,17 +109,17 @@
protected:
// Subclasses select the trace to replace. Returns false if no replacement
// is to happen, otherwise stores the index of the trace to replace in
// *index.
- virtual bool select_replacement(uint32_t *index) = 0;
+ virtual bool select_replacement(uint32_t* index) = 0;
const uint32_t _size;
private:
// The current garbage traces. A fixed-size ring buffer.
- StackTraceData **_garbage_traces;
+ StackTraceData** _garbage_traces;
};
// Keep statistical sample of traces over the lifetime of the server.
// When the buffer is full, replace a random entry with probability
// 1/samples_seen. This strategy tends towards preserving the most frequently
@@ -180,31 +190,31 @@
// Each object that we profile is stored as trace with the thread_id.
class StackTraceStorage : public CHeapObj<mtInternal> {
public:
// The function that gets called to add a trace to the list of
// traces we are maintaining.
- void add_trace(jvmtiStackTrace *trace, oop o);
+ void add_trace(jvmtiStackTrace* trace, oop o);
// The function that gets called by the client to retrieve the list
// of stack traces. Passes a jvmtiStackTraces which will get mutated.
- void get_all_stack_traces(jvmtiStackTraces *traces);
+ void get_all_stack_traces(jvmtiStackTraces* traces);
// The function that gets called by the client to retrieve the list
// of stack traces. Passes a jvmtiStackTraces which will get mutated.
- void get_garbage_stack_traces(jvmtiStackTraces *traces);
+ void get_garbage_stack_traces(jvmtiStackTraces* traces);
// The function that gets called by the client to retrieve the list
// of stack traces. Passes a jvmtiStackTraces which will get mutated.
- void get_frequent_garbage_stack_traces(jvmtiStackTraces *traces);
+ void get_frequent_garbage_stack_traces(jvmtiStackTraces* traces);
// The function that gets called by the client to retrieve the list
// of stack traces. Passes a jvmtiStackTraces which will get mutated.
- void get_cached_stack_traces(jvmtiStackTraces *traces);
+ void get_cached_stack_traces(jvmtiStackTraces* traces);
// Executes whenever weak references are traversed. is_alive tells
// you if the given oop is still reachable and live.
- void weak_oops_do(BoolObjectClosure* is_alive, OopClosure *f);
+ void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
~StackTraceStorage();
StackTraceStorage();
static StackTraceStorage* storage() {
@@ -234,20 +244,20 @@
bool initialized() { return _initialized; }
private:
// The traces currently sampled.
- GrowableArray<StackTraceData> *_allocated_traces;
+ GrowableArray<StackTraceDataWithOop>* _allocated_traces;
// The traces currently sampled.
- GrowableArray<StackTraceData> *_traces_on_last_full_gc;
+ GrowableArray<StackTraceDataWithOop>* _traces_on_last_full_gc;
// Recent garbage traces.
- MostRecentGarbageTraces *_recent_garbage_traces;
+ MostRecentGarbageTraces* _recent_garbage_traces;
// Frequent garbage traces.
- FrequentGarbageTraces *_frequent_garbage_traces;
+ FrequentGarbageTraces* _frequent_garbage_traces;
// Heap Sampling statistics.
jvmtiHeapSamplingStats _stats;
// Maximum amount of storage provided by the JVMTI call initialize_profiling.
@@ -259,44 +269,44 @@
// Support functions and classes for copying data to the external
// world.
class StackTraceDataCopier {
public:
virtual int size() const = 0;
- virtual const StackTraceData *get(uint32_t i) const = 0;
+ virtual const StackTraceData* get(uint32_t i) const = 0;
};
class LiveStackTraceDataCopier : public StackTraceDataCopier {
public:
- LiveStackTraceDataCopier(GrowableArray<StackTraceData> *data) :
+ LiveStackTraceDataCopier(GrowableArray<StackTraceDataWithOop>* data) :
_data(data) {}
int size() const { return _data ? _data->length() : 0; }
- const StackTraceData *get(uint32_t i) const { return _data->adr_at(i); }
+ const StackTraceData* get(uint32_t i) const { return _data->adr_at(i); }
private:
- GrowableArray<StackTraceData> *_data;
+ GrowableArray<StackTraceDataWithOop>* _data;
};
class GarbageStackTraceDataCopier : public StackTraceDataCopier {
public:
- GarbageStackTraceDataCopier(StackTraceData **data, int size) :
+ GarbageStackTraceDataCopier(StackTraceData** data, int size) :
_data(data), _size(size) {}
int size() const { return _size; }
- const StackTraceData *get(uint32_t i) const { return _data[i]; }
+ const StackTraceData* get(uint32_t i) const { return _data[i]; }
private:
- StackTraceData **_data;
+ StackTraceData** _data;
int _size;
};
// Copies from StackTraceData to jvmtiStackTrace.
- bool deep_copy(jvmtiStackTrace *to, const StackTraceData *from);
+ bool deep_copy(jvmtiStackTrace* to, const StackTraceData* from);
// Creates a deep copy of the list of StackTraceData.
void copy_stack_traces(const StackTraceDataCopier &copier,
- jvmtiStackTraces *traces);
+ jvmtiStackTraces* traces);
- void store_garbage_trace(const StackTraceData &trace);
+ void store_garbage_trace(const StackTraceDataWithOop &trace);
void free_garbage();
void free_storage();
void reset();
@@ -325,14 +335,14 @@
_max_gc_storage = 0;
_initialized = false;
}
void StackTraceStorage::free_garbage() {
- StackTraceData **recent_garbage = NULL;
+ StackTraceData** recent_garbage = NULL;
uint32_t recent_size = 0;
- StackTraceData **frequent_garbage = NULL;
+ StackTraceData** frequent_garbage = NULL;
uint32_t frequent_size = 0;
if (_recent_garbage_traces != NULL) {
recent_garbage = _recent_garbage_traces->get_traces();
recent_size = _recent_garbage_traces->size();
@@ -344,11 +354,11 @@
}
// Simple solution since this happens at exit.
// Go through the recent and remove any that only are referenced there.
for (uint32_t i = 0; i < recent_size; i++) {
- StackTraceData *trace = recent_garbage[i];
+ StackTraceData* trace = recent_garbage[i];
if (trace != NULL) {
trace->references--;
if (trace->references == 0) {
StackTraceData::free_data(trace);
@@ -356,11 +366,11 @@
}
}
// Then go through the frequent and remove those that are now only there.
for (uint32_t i = 0; i < frequent_size; i++) {
- StackTraceData *trace = frequent_garbage[i];
+ StackTraceData* trace = frequent_garbage[i];
if (trace != NULL) {
trace->references--;
if (trace->references == 0) {
StackTraceData::free_data(trace);
@@ -393,36 +403,36 @@
if (_initialized) {
return;
}
_allocated_traces = new (ResourceObj::C_HEAP, mtInternal)
- GrowableArray<StackTraceData>(128, true);
+ GrowableArray<StackTraceDataWithOop>(128, true);
_traces_on_last_full_gc = new (ResourceObj::C_HEAP, mtInternal)
- GrowableArray<StackTraceData>(128, true);
+ GrowableArray<StackTraceDataWithOop>(128, true);
_recent_garbage_traces = new MostRecentGarbageTraces(max_gc_storage);
_frequent_garbage_traces = new FrequentGarbageTraces(max_gc_storage);
_max_gc_storage = max_gc_storage;
_initialized = true;
}
-void StackTraceStorage::add_trace(jvmtiStackTrace *trace, oop o) {
+void StackTraceStorage::add_trace(jvmtiStackTrace* trace, oop o) {
MutexLocker mu(HeapMonitorStorage_lock);
// Last minute check on initialization here in case:
// Between the moment object_alloc_do_sample's check for initialization
// and now, there was a stop() that deleted the data.
if (_initialized) {
- StackTraceData new_data(trace, o);
+ StackTraceDataWithOop new_data(trace, o);
_stats.sample_count++;
_stats.stack_depth_accumulation += trace->frame_count;
_allocated_traces->append(new_data);
}
}
-void StackTraceStorage::weak_oops_do(BoolObjectClosure *is_alive,
- OopClosure *f) {
+void StackTraceStorage::weak_oops_do(BoolObjectClosure* is_alive,
+ OopClosure* f) {
MutexLocker mu(HeapMonitorStorage_lock);
size_t count = 0;
if (_initialized) {
int len = _allocated_traces->length();
@@ -430,14 +440,14 @@
// Compact the oop traces. Moves the live oops to the beginning of the
// growable array, potentially overwriting the dead ones.
int curr_pos = 0;
for (int i = 0; i < len; i++) {
- StackTraceData &trace = _allocated_traces->at(i);
- oop value = trace.obj;
- if (Universe::heap()->is_in_reserved(value)
- && is_alive->do_object_b(value)) {
+ StackTraceDataWithOop &trace = _allocated_traces->at(i);
+ oop value = RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(
+ &trace.obj);
+ if (is_alive->do_object_b(value)) {
// Update the oop to point to the new object if it is still alive.
f->do_oop(&(trace.obj));
// Copy the old trace, if it is still live.
_allocated_traces->at_put(curr_pos++, trace);
@@ -453,11 +463,11 @@
}
}
// Zero out remaining array elements. Even though the call to trunc_to
// below truncates these values, zeroing them out is good practice.
- StackTraceData zero_trace;
+ StackTraceDataWithOop zero_trace;
for (int i = curr_pos; i < len; i++) {
_allocated_traces->at_put(i, zero_trace);
}
// Set the array's length to the number of live elements.
@@ -465,13 +475,13 @@
}
log_develop_trace(gc, ref)("Clearing HeapMonitoring weak reference (" INT64_FORMAT ")", count);
}
-bool StackTraceStorage::deep_copy(jvmtiStackTrace *to,
- const StackTraceData *from) {
- const jvmtiStackTrace *src = from->trace;
+bool StackTraceStorage::deep_copy(jvmtiStackTrace* to,
+ const StackTraceData* from) {
+ const jvmtiStackTrace* src = from->trace;
*to = *src;
to->frames =
NEW_C_HEAP_ARRAY(jvmtiFrameInfo, src->frame_count, mtInternal);
@@ -486,11 +496,11 @@
}
// Called by the outside world; returns a copy of the stack traces
// (because we could be replacing them as the user handles them).
// The array is secretly null-terminated (to make it easier to reclaim).
-void StackTraceStorage::get_all_stack_traces(jvmtiStackTraces *traces) {
+void StackTraceStorage::get_all_stack_traces(jvmtiStackTraces* traces) {
if (!_allocated_traces) {
traces->stack_traces = NULL;
traces->trace_count = 0;
return;
}
@@ -498,11 +508,11 @@
LiveStackTraceDataCopier copier(_allocated_traces);
copy_stack_traces(copier, traces);
}
// See comment on get_all_stack_traces
-void StackTraceStorage::get_garbage_stack_traces(jvmtiStackTraces *traces) {
+void StackTraceStorage::get_garbage_stack_traces(jvmtiStackTraces* traces) {
if (!_recent_garbage_traces) {
traces->stack_traces = NULL;
traces->trace_count = 0;
return;
}
@@ -512,11 +522,11 @@
copy_stack_traces(copier, traces);
}
// See comment on get_all_stack_traces
void StackTraceStorage::get_frequent_garbage_stack_traces(
- jvmtiStackTraces *traces) {
+ jvmtiStackTraces* traces) {
if (!_frequent_garbage_traces) {
traces->stack_traces = NULL;
traces->trace_count = 0;
return;
}
@@ -525,11 +535,11 @@
_frequent_garbage_traces->size());
copy_stack_traces(copier, traces);
}
// See comment on get_all_stack_traces
-void StackTraceStorage::get_cached_stack_traces(jvmtiStackTraces *traces) {
+void StackTraceStorage::get_cached_stack_traces(jvmtiStackTraces* traces) {
if (!_traces_on_last_full_gc) {
traces->stack_traces = NULL;
traces->trace_count = 0;
return;
}
@@ -537,17 +547,17 @@
LiveStackTraceDataCopier copier(_traces_on_last_full_gc);
copy_stack_traces(copier, traces);
}
void StackTraceStorage::copy_stack_traces(const StackTraceDataCopier &copier,
- jvmtiStackTraces *traces) {
+ jvmtiStackTraces* traces) {
MutexLocker mu(HeapMonitorStorage_lock);
int len = copier.size();
// Create a new array to store the StackTraceData objects.
// + 1 for a NULL at the end.
- jvmtiStackTrace *t =
+ jvmtiStackTrace* t =
NEW_C_HEAP_ARRAY(jvmtiStackTrace, len + 1, mtInternal);
if (t == NULL) {
traces->stack_traces = NULL;
traces->trace_count = 0;
return;
@@ -556,13 +566,13 @@
memset(t, 0, (len + 1) * sizeof(*t));
// Copy the StackTraceData objects into the new array.
int trace_count = 0;
for (int i = 0; i < len; i++) {
- const StackTraceData *stack_trace = copier.get(i);
+ const StackTraceData* stack_trace = copier.get(i);
if (stack_trace != NULL) {
- jvmtiStackTrace *to = &t[trace_count];
+ jvmtiStackTrace* to = &t[trace_count];
if (!deep_copy(to, stack_trace)) {
continue;
}
trace_count++;
}
@@ -570,13 +580,12 @@
traces->stack_traces = t;
traces->trace_count = trace_count;
}
-void StackTraceStorage::store_garbage_trace(const StackTraceData &trace) {
- StackTraceData *new_trace = new StackTraceData();
- *new_trace = trace;
+void StackTraceStorage::store_garbage_trace(const StackTraceDataWithOop &trace) {
+ StackTraceData* new_trace = new StackTraceData(trace.trace);
bool accepted = _recent_garbage_traces->store_trace(new_trace);
// Accepted is on the right of the boolean to force the store_trace to happen.
accepted = _frequent_garbage_traces->store_trace(new_trace) || accepted;
@@ -587,49 +596,49 @@
}
_stats.garbage_collected_samples++;
}
-void HeapMonitoring::get_live_traces(jvmtiStackTraces *traces) {
+void HeapMonitoring::get_live_traces(jvmtiStackTraces* traces) {
StackTraceStorage::storage()->get_all_stack_traces(traces);
}
-void HeapMonitoring::get_sampling_statistics(jvmtiHeapSamplingStats *stats) {
+void HeapMonitoring::get_sampling_statistics(jvmtiHeapSamplingStats* stats) {
const jvmtiHeapSamplingStats& internal_stats =
StackTraceStorage::storage()->get_heap_sampling_stats();
*stats = internal_stats;
}
-void HeapMonitoring::get_frequent_garbage_traces(jvmtiStackTraces *traces) {
+void HeapMonitoring::get_frequent_garbage_traces(jvmtiStackTraces* traces) {
StackTraceStorage::storage()->get_frequent_garbage_stack_traces(traces);
}
-void HeapMonitoring::get_garbage_traces(jvmtiStackTraces *traces) {
+void HeapMonitoring::get_garbage_traces(jvmtiStackTraces* traces) {
StackTraceStorage::storage()->get_garbage_stack_traces(traces);
}
-void HeapMonitoring::get_cached_traces(jvmtiStackTraces *traces) {
+void HeapMonitoring::get_cached_traces(jvmtiStackTraces* traces) {
StackTraceStorage::storage()->get_cached_stack_traces(traces);
}
-void HeapMonitoring::release_traces(jvmtiStackTraces *traces) {
+void HeapMonitoring::release_traces(jvmtiStackTraces* traces) {
jint trace_count = traces->trace_count;
- jvmtiStackTrace *stack_traces = traces->stack_traces;
+ jvmtiStackTrace* stack_traces = traces->stack_traces;
for (jint i = 0; i < trace_count; i++) {
- jvmtiStackTrace *current_trace = stack_traces + i;
+ jvmtiStackTrace* current_trace = stack_traces + i;
FREE_C_HEAP_ARRAY(jvmtiFrameInfo, current_trace->frames);
}
FREE_C_HEAP_ARRAY(jvmtiStackTrace, traces->stack_traces);
traces->trace_count = 0;
traces->stack_traces = NULL;
}
// Invoked by the GC to clean up old stack traces and remove old arrays
// of instrumentation that are still lying around.
-void HeapMonitoring::weak_oops_do(BoolObjectClosure* is_alive, OopClosure *f) {
+void HeapMonitoring::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
StackTraceStorage::storage()->weak_oops_do(is_alive, f);
}
void HeapMonitoring::initialize_profiling(jint monitoring_rate,
@@ -648,11 +657,11 @@
for (int i = 0; i < (1 << FastLogNumBits); i++) {
double half_way = static_cast<double>(i + 0.5);
_log_table[i] = (log(1.0 + half_way / (1 << FastLogNumBits)) / log(2.0));
}
- JavaThread *t = static_cast<JavaThread *>(Thread::current());
+ JavaThread* t = static_cast<JavaThread*>(Thread::current());
_rnd = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(t));
if (_rnd == 0) {
_rnd = 1;
}
@@ -675,11 +684,11 @@
// q = 1 - p = exp(-mx)
// log_e(q) = -mx
// -log_e(q)/m = x
// log_2(q) * (-log_e(2) * 1/m) = x
// In the code, q is actually in the range 1 to 2**26, hence the -26 below
-void HeapMonitoring::pick_next_sample(size_t *ptr) {
+void HeapMonitoring::pick_next_sample(size_t* ptr) {
_rnd = next_random(_rnd);
// Take the top 26 bits as the random number
// (This plus a 1<<58 sampling bound gives a max possible step of
// 5194297183973780480 bytes. In this case,
// for sample_parameter = 1<<19, max possible step is
@@ -700,22 +709,22 @@
*ptr = rate;
StackTraceStorage::storage()->accumulate_sample_rate(rate);
}
-void HeapMonitoring::object_alloc_do_sample(Thread *t, oopDesc *o, intx byte_size) {
- JavaThread *thread = static_cast<JavaThread *>(t);
+void HeapMonitoring::object_alloc_do_sample(Thread* t, oopDesc* o, intx byte_size) {
+ JavaThread* thread = static_cast<JavaThread*>(t);
if (StackTraceStorage::storage()->initialized()) {
assert(t->is_Java_thread(), "non-Java thread passed to do_sample");
- JavaThread *thread = static_cast<JavaThread *>(t);
+ JavaThread* thread = static_cast<JavaThread*>(t);
- jvmtiStackTrace *trace = NEW_C_HEAP_OBJ(jvmtiStackTrace, mtInternal);
+ jvmtiStackTrace* trace = NEW_C_HEAP_OBJ(jvmtiStackTrace, mtInternal);
if (trace == NULL) {
return;
}
- jvmtiFrameInfo *frames =
+ jvmtiFrameInfo* frames =
NEW_C_HEAP_ARRAY(jvmtiFrameInfo, MaxStackDepth, mtInternal);
if (frames == NULL) {
FREE_C_HEAP_OBJ(trace);
return;
< prev index next >