< 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 >