8235573: Move JFR ObjectSample oop into OopStorage
Reviewed-by: mgronlun, dholmes, kbarrett
This commit is contained in:
parent
c200b4f1cb
commit
97bbbbba51
@ -38,7 +38,7 @@ class OopStorageSet : public AllStatic {
|
||||
public:
|
||||
// Must be updated when new OopStorages are introduced
|
||||
static const uint strong_count = 2;
|
||||
static const uint weak_count = 4;
|
||||
static const uint weak_count = 4 JFR_ONLY(+ 1);
|
||||
static const uint all_count = strong_count + weak_count;
|
||||
|
||||
private:
|
||||
|
@ -27,19 +27,15 @@
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
#endif // INCLUDE_JFR
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
// serial_phase_count is 0 if JFR and JVMTI are both not built,
|
||||
// serial_phase_count is 0 if JVMTI is not built,
|
||||
// requiring some code to be careful to avoid tautological checks
|
||||
// that some compilers warn about.
|
||||
|
||||
#define HAVE_SERIAL_PHASES (INCLUDE_JVMTI || INCLUDE_JFR)
|
||||
#define HAVE_SERIAL_PHASES INCLUDE_JVMTI
|
||||
|
||||
WeakProcessorPhases::Phase WeakProcessorPhases::serial_phase(uint value) {
|
||||
#if HAVE_SERIAL_PHASES
|
||||
@ -109,7 +105,6 @@ void WeakProcessorPhases::Iterator::verify_dereferenceable() const {
|
||||
const char* WeakProcessorPhases::description(Phase phase) {
|
||||
switch (phase) {
|
||||
JVMTI_ONLY(case jvmti: return "JVMTI weak processing";)
|
||||
JFR_ONLY(case jfr: return "JFR weak processing";)
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return "Invalid serial weak processing phase";
|
||||
@ -119,7 +114,6 @@ const char* WeakProcessorPhases::description(Phase phase) {
|
||||
WeakProcessorPhases::Processor WeakProcessorPhases::processor(Phase phase) {
|
||||
switch (phase) {
|
||||
JVMTI_ONLY(case jvmti: return &JvmtiExport::weak_oops_do;)
|
||||
JFR_ONLY(case jfr: return &Jfr::weak_oops_do;)
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
|
@ -41,15 +41,14 @@ public:
|
||||
typedef void (*Processor)(BoolObjectClosure*, OopClosure*);
|
||||
|
||||
enum Phase {
|
||||
// Serial phases.
|
||||
JVMTI_ONLY(jvmti JFR_ONLY(COMMA))
|
||||
JFR_ONLY(jfr)
|
||||
// Serial phase.
|
||||
JVMTI_ONLY(jvmti)
|
||||
|
||||
// Additional implicit phase values follow for oopstorages.
|
||||
};
|
||||
|
||||
static const uint serial_phase_start = 0;
|
||||
static const uint serial_phase_count = 0 JVMTI_ONLY(+ 1) JFR_ONLY(+ 1);
|
||||
static const uint serial_phase_count = 0 JVMTI_ONLY(+ 1);
|
||||
static const uint oopstorage_phase_start = serial_phase_count;
|
||||
static const uint oopstorage_phase_count = OopStorageSet::weak_count;
|
||||
static const uint phase_count = serial_phase_count + oopstorage_phase_count;
|
||||
|
@ -25,7 +25,6 @@
|
||||
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHPHASETIMINGS_HPP
|
||||
#define SHARE_GC_SHENANDOAH_SHENANDOAHPHASETIMINGS_HPP
|
||||
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "gc/shenandoah/shenandoahNumberSeq.hpp"
|
||||
#include "gc/shared/workerDataArray.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
@ -43,7 +42,6 @@ class outputStream;
|
||||
f(CNT_PREFIX ## ObjectSynchronizerRoots, DESC_PREFIX "Synchronizer Roots") \
|
||||
f(CNT_PREFIX ## CLDGRoots, DESC_PREFIX "CLDG Roots") \
|
||||
f(CNT_PREFIX ## JVMTIWeakRoots, DESC_PREFIX "JVMTI Weak Roots") \
|
||||
f(CNT_PREFIX ## JFRWeakRoots, DESC_PREFIX "JFR Weak Roots") \
|
||||
f(CNT_PREFIX ## StringDedupTableRoots, DESC_PREFIX "Dedup Table Roots") \
|
||||
f(CNT_PREFIX ## StringDedupQueueRoots, DESC_PREFIX "Dedup Queue Roots") \
|
||||
f(CNT_PREFIX ## FinishQueues, DESC_PREFIX "Finish Queues") \
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "gc/shenandoah/shenandoahPhaseTimings.hpp"
|
||||
#include "gc/shenandoah/shenandoahStringDedup.hpp"
|
||||
#include "gc/shenandoah/shenandoahVMOperations.hpp"
|
||||
#include "jfr/jfr.hpp"
|
||||
#include "memory/iterator.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
@ -81,15 +80,8 @@ ShenandoahJVMTIWeakRoot::ShenandoahJVMTIWeakRoot(ShenandoahPhaseTimings::Phase p
|
||||
}
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
#if INCLUDE_JFR
|
||||
ShenandoahJFRWeakRoot::ShenandoahJFRWeakRoot(ShenandoahPhaseTimings::Phase phase) :
|
||||
ShenandoahWeakSerialRoot(&Jfr::weak_oops_do, phase, ShenandoahPhaseTimings::JFRWeakRoots) {
|
||||
}
|
||||
#endif // INCLUDE_JFR
|
||||
|
||||
void ShenandoahSerialWeakRoots::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id) {
|
||||
JVMTI_ONLY(_jvmti_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);)
|
||||
JFR_ONLY(_jfr_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);)
|
||||
}
|
||||
|
||||
void ShenandoahSerialWeakRoots::weak_oops_do(OopClosure* cl, uint worker_id) {
|
||||
|
@ -79,21 +79,12 @@ public:
|
||||
};
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
#if INCLUDE_JFR
|
||||
class ShenandoahJFRWeakRoot : public ShenandoahWeakSerialRoot {
|
||||
public:
|
||||
ShenandoahJFRWeakRoot(ShenandoahPhaseTimings::Phase phase);
|
||||
};
|
||||
#endif // INCLUDE_JFR
|
||||
|
||||
class ShenandoahSerialWeakRoots {
|
||||
private:
|
||||
JVMTI_ONLY(ShenandoahJVMTIWeakRoot _jvmti_weak_roots;)
|
||||
JFR_ONLY(ShenandoahJFRWeakRoot _jfr_weak_roots;)
|
||||
public:
|
||||
ShenandoahSerialWeakRoots(ShenandoahPhaseTimings::Phase phase)
|
||||
JVMTI_ONLY(: _jvmti_weak_roots(phase))
|
||||
JFR_ONLY(NOT_JVMTI(:) JVMTI_ONLY(COMMA) _jfr_weak_roots(phase))
|
||||
{};
|
||||
|
||||
void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, uint worker_id);
|
||||
|
@ -50,9 +50,6 @@
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
#endif
|
||||
|
||||
static const ZStatSubPhase ZSubPhasePauseRootsSetup("Pause Roots Setup");
|
||||
static const ZStatSubPhase ZSubPhasePauseRoots("Pause Roots");
|
||||
@ -74,7 +71,6 @@ static const ZStatSubPhase ZSubPhasePauseWeakRootsSetup("Pause Weak Roots Setup"
|
||||
static const ZStatSubPhase ZSubPhasePauseWeakRoots("Pause Weak Roots");
|
||||
static const ZStatSubPhase ZSubPhasePauseWeakRootsTeardown("Pause Weak Roots Teardown");
|
||||
static const ZStatSubPhase ZSubPhasePauseWeakRootsJVMTIWeakExport("Pause Weak Roots JVMTIWeakExport");
|
||||
static const ZStatSubPhase ZSubPhasePauseWeakRootsJFRWeak("Pause Weak Roots JFRWeak");
|
||||
|
||||
static const ZStatSubPhase ZSubPhaseConcurrentWeakRoots("Concurrent Weak Roots");
|
||||
static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsOopStorageSet("Concurrent Weak Roots OopStorageSet");
|
||||
@ -295,8 +291,7 @@ void ZConcurrentRootsIterator::oops_do(ZRootsIteratorClosure* cl) {
|
||||
}
|
||||
|
||||
ZWeakRootsIterator::ZWeakRootsIterator() :
|
||||
_jvmti_weak_export(this),
|
||||
_jfr_weak(this) {
|
||||
_jvmti_weak_export(this) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
|
||||
ZStatTimer timer(ZSubPhasePauseWeakRootsSetup);
|
||||
}
|
||||
@ -310,17 +305,9 @@ void ZWeakRootsIterator::do_jvmti_weak_export(BoolObjectClosure* is_alive, ZRoot
|
||||
JvmtiExport::weak_oops_do(is_alive, cl);
|
||||
}
|
||||
|
||||
void ZWeakRootsIterator::do_jfr_weak(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl) {
|
||||
#if INCLUDE_JFR
|
||||
ZStatTimer timer(ZSubPhasePauseWeakRootsJFRWeak);
|
||||
Jfr::weak_oops_do(is_alive, cl);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ZWeakRootsIterator::weak_oops_do(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl) {
|
||||
ZStatTimer timer(ZSubPhasePauseWeakRoots);
|
||||
_jvmti_weak_export.weak_oops_do(is_alive, cl);
|
||||
_jfr_weak.weak_oops_do(is_alive, cl);
|
||||
}
|
||||
|
||||
void ZWeakRootsIterator::oops_do(ZRootsIteratorClosure* cl) {
|
||||
|
@ -170,10 +170,8 @@ public:
|
||||
class ZWeakRootsIterator {
|
||||
private:
|
||||
void do_jvmti_weak_export(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl);
|
||||
void do_jfr_weak(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl);
|
||||
|
||||
ZSerialWeakOopsDo<ZWeakRootsIterator, &ZWeakRootsIterator::do_jvmti_weak_export> _jvmti_weak_export;
|
||||
ZSerialWeakOopsDo<ZWeakRootsIterator, &ZWeakRootsIterator::do_jfr_weak> _jfr_weak;
|
||||
|
||||
public:
|
||||
ZWeakRootsIterator();
|
||||
|
@ -102,12 +102,6 @@ void Jfr::on_vm_error_report(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
void Jfr::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
if (LeakProfiler::is_running()) {
|
||||
LeakProfiler::weak_oops_do(is_alive, f);
|
||||
}
|
||||
}
|
||||
|
||||
bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* delimiter) {
|
||||
return JfrOptionSet::parse_flight_recorder_option(option, delimiter);
|
||||
}
|
||||
|
@ -28,9 +28,7 @@
|
||||
#include "jni.h"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class BoolObjectClosure;
|
||||
class JavaThread;
|
||||
class OopClosure;
|
||||
class Thread;
|
||||
|
||||
extern "C" void JNICALL jfr_register_natives(JNIEnv*, jclass);
|
||||
@ -53,7 +51,6 @@ class Jfr : AllStatic {
|
||||
static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter);
|
||||
static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter);
|
||||
static void on_vm_error_report(outputStream* st);
|
||||
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
|
||||
static void exclude_thread(Thread* thread);
|
||||
static bool is_excluded(Thread* thread);
|
||||
static void include_thread(Thread* thread);
|
||||
|
@ -89,14 +89,6 @@ void LeakProfiler::emit_events(int64_t cutoff_ticks, bool emit_all, bool skip_bf
|
||||
ObjectSampler::release();
|
||||
}
|
||||
|
||||
void LeakProfiler::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(),
|
||||
"Leak Profiler::oops_do(...) may only be called during safepoint");
|
||||
if (is_running()) {
|
||||
ObjectSampler::weak_oops_do(is_alive, f);
|
||||
}
|
||||
}
|
||||
|
||||
void LeakProfiler::sample(HeapWord* object, size_t size, JavaThread* thread) {
|
||||
assert(is_running(), "invariant");
|
||||
assert(thread != NULL, "invariant");
|
||||
|
@ -27,8 +27,6 @@
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class BoolObjectClosure;
|
||||
class OopClosure;
|
||||
class JavaThread;
|
||||
|
||||
class LeakProfiler : public AllStatic {
|
||||
@ -39,9 +37,6 @@ class LeakProfiler : public AllStatic {
|
||||
|
||||
static void emit_events(int64_t cutoff_ticks, bool emit_all, bool skip_bfs);
|
||||
static void sample(HeapWord* object, size_t size, JavaThread* thread);
|
||||
|
||||
// Called by GC
|
||||
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
|
||||
};
|
||||
|
||||
#endif // SHARE_JFR_LEAKPROFILER_LEAKPROFILER_HPP
|
||||
|
@ -23,16 +23,36 @@
|
||||
*/
|
||||
#include "precompiled.hpp"
|
||||
#include "jfr/leakprofiler/sampling/objectSample.hpp"
|
||||
#include "oops/access.inline.hpp"
|
||||
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
|
||||
#include "oops/weakHandle.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
|
||||
const oop ObjectSample::object() const {
|
||||
return NativeAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(&_object);
|
||||
void ObjectSample::reset() {
|
||||
release();
|
||||
set_stack_trace_id(0);
|
||||
set_stack_trace_hash(0);
|
||||
release_references();
|
||||
}
|
||||
|
||||
const oop ObjectSample::object_raw() const {
|
||||
return RawAccess<>::oop_load(&_object);
|
||||
const oop ObjectSample::object() const {
|
||||
return _object.resolve();
|
||||
}
|
||||
|
||||
bool ObjectSample::is_dead() const {
|
||||
return _object.peek() == NULL;
|
||||
}
|
||||
|
||||
const oop* ObjectSample::object_addr() const {
|
||||
return _object.ptr_raw();
|
||||
}
|
||||
|
||||
void ObjectSample::set_object(oop object) {
|
||||
NativeAccess<ON_PHANTOM_OOP_REF>::oop_store(&_object, object);
|
||||
assert(_object.is_empty(), "should be empty");
|
||||
Handle h(Thread::current(), object);
|
||||
_object = WeakHandle(ObjectSampler::oop_storage(), h);
|
||||
}
|
||||
|
||||
void ObjectSample::release() {
|
||||
_object.release(ObjectSampler::oop_storage());
|
||||
_object = WeakHandle();
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "jfr/utilities/jfrTypes.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "oops/weakHandle.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
|
||||
/*
|
||||
@ -48,7 +49,7 @@ class ObjectSample : public JfrCHeapObj {
|
||||
JfrBlobHandle _stacktrace;
|
||||
JfrBlobHandle _thread;
|
||||
JfrBlobHandle _type_set;
|
||||
oop _object;
|
||||
WeakHandle _object;
|
||||
Ticks _allocation_time;
|
||||
traceid _stack_trace_id;
|
||||
traceid _thread_id;
|
||||
@ -64,12 +65,7 @@ class ObjectSample : public JfrCHeapObj {
|
||||
_type_set.~JfrBlobHandle();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_object = NULL;
|
||||
set_stack_trace_id(0);
|
||||
set_stack_trace_hash(0);
|
||||
release_references();
|
||||
}
|
||||
void reset();
|
||||
|
||||
public:
|
||||
ObjectSample() : _next(NULL),
|
||||
@ -77,7 +73,6 @@ class ObjectSample : public JfrCHeapObj {
|
||||
_stacktrace(),
|
||||
_thread(),
|
||||
_type_set(),
|
||||
_object(NULL),
|
||||
_allocation_time(),
|
||||
_stack_trace_id(0),
|
||||
_thread_id(0),
|
||||
@ -103,17 +98,14 @@ class ObjectSample : public JfrCHeapObj {
|
||||
_previous = prev;
|
||||
}
|
||||
|
||||
bool is_dead() const {
|
||||
return object() == NULL;
|
||||
}
|
||||
bool is_dead() const;
|
||||
|
||||
const oop object() const;
|
||||
const oop object_raw() const;
|
||||
void set_object(oop object);
|
||||
|
||||
const oop* object_addr() const {
|
||||
return &_object;
|
||||
}
|
||||
const oop* object_addr() const;
|
||||
|
||||
void release();
|
||||
|
||||
int index() const {
|
||||
return _index;
|
||||
|
@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "jfr/jfrEvents.hpp"
|
||||
#include "jfr/leakprofiler/sampling/objectSample.hpp"
|
||||
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
|
||||
@ -41,6 +43,40 @@
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
// Timestamp of when the gc last processed the set of sampled objects.
|
||||
static JfrTicks _last_sweep;
|
||||
|
||||
// Condition variable to communicate that some sampled objects have been cleared by the gc
|
||||
// and can therefore be removed from the sample priority queue.
|
||||
static bool volatile _dead_samples = false;
|
||||
|
||||
// The OopStorage instance is used to hold weak references to sampled objects.
|
||||
// It is constructed and registered during VM initialization. This is a singleton
|
||||
// that persist independent of the state of the ObjectSampler.
|
||||
static OopStorage* _oop_storage = NULL;
|
||||
|
||||
OopStorage* ObjectSampler::oop_storage() { return _oop_storage; }
|
||||
|
||||
// Callback invoked by the GC after an iteration over the oop storage
|
||||
// that may have cleared dead referents. num_dead is the number of entries
|
||||
// already NULL or cleared by the iteration.
|
||||
void ObjectSampler::oop_storage_gc_notification(size_t num_dead) {
|
||||
if (num_dead != 0) {
|
||||
// The ObjectSampler instance may have already been cleaned or a new
|
||||
// instance was created concurrently. This allows for a small race where cleaning
|
||||
// could be done again.
|
||||
Atomic::store(&_dead_samples, true);
|
||||
_last_sweep = JfrTicks::now();
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectSampler::create_oop_storage() {
|
||||
_oop_storage = OopStorageSet::create_weak("Weak JFR Old Object Samples");
|
||||
assert(_oop_storage != NULL, "invariant");
|
||||
_oop_storage->register_num_dead_callback(&oop_storage_gc_notification);
|
||||
return true;
|
||||
}
|
||||
|
||||
static ObjectSampler* _instance = NULL;
|
||||
|
||||
static ObjectSampler& instance() {
|
||||
@ -49,13 +85,14 @@ static ObjectSampler& instance() {
|
||||
}
|
||||
|
||||
ObjectSampler::ObjectSampler(size_t size) :
|
||||
_priority_queue(new SamplePriorityQueue(size)),
|
||||
_list(new SampleList(size)),
|
||||
_last_sweep(JfrTicks::now()),
|
||||
_total_allocated(0),
|
||||
_threshold(0),
|
||||
_size(size),
|
||||
_dead_samples(false) {}
|
||||
_priority_queue(new SamplePriorityQueue(size)),
|
||||
_list(new SampleList(size)),
|
||||
_total_allocated(0),
|
||||
_threshold(0),
|
||||
_size(size) {
|
||||
_last_sweep = JfrTicks::now();
|
||||
Atomic::store(&_dead_samples, false);
|
||||
}
|
||||
|
||||
ObjectSampler::~ObjectSampler() {
|
||||
delete _priority_queue;
|
||||
@ -66,6 +103,7 @@ ObjectSampler::~ObjectSampler() {
|
||||
|
||||
bool ObjectSampler::create(size_t size) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||
assert(_oop_storage != NULL, "should be already created");
|
||||
assert(_instance == NULL, "invariant");
|
||||
_instance = new ObjectSampler(size);
|
||||
return _instance != NULL;
|
||||
@ -92,13 +130,11 @@ void ObjectSampler::destroy() {
|
||||
static volatile int _lock = 0;
|
||||
|
||||
ObjectSampler* ObjectSampler::acquire() {
|
||||
assert(is_created(), "invariant");
|
||||
while (Atomic::cmpxchg(&_lock, 0, 1) == 1) {}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
void ObjectSampler::release() {
|
||||
assert(is_created(), "invariant");
|
||||
OrderAccess::fence();
|
||||
_lock = 0;
|
||||
}
|
||||
@ -150,9 +186,11 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, Java
|
||||
assert(thread != NULL, "invariant");
|
||||
assert(thread->jfr_thread_local()->has_thread_blob(), "invariant");
|
||||
|
||||
if (_dead_samples) {
|
||||
if (Atomic::load(&_dead_samples)) {
|
||||
// There's a small race where a GC scan might reset this to true, potentially
|
||||
// causing a back-to-back scavenge.
|
||||
Atomic::store(&_dead_samples, false);
|
||||
scavenge();
|
||||
assert(!_dead_samples, "invariant");
|
||||
}
|
||||
|
||||
_total_allocated += allocated;
|
||||
@ -199,12 +237,13 @@ void ObjectSampler::scavenge() {
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
_dead_samples = false;
|
||||
}
|
||||
|
||||
void ObjectSampler::remove_dead(ObjectSample* sample) {
|
||||
assert(sample != NULL, "invariant");
|
||||
assert(sample->is_dead(), "invariant");
|
||||
sample->release();
|
||||
|
||||
ObjectSample* const previous = sample->prev();
|
||||
// push span onto previous
|
||||
if (previous != NULL) {
|
||||
@ -216,27 +255,6 @@ void ObjectSampler::remove_dead(ObjectSample* sample) {
|
||||
_list->release(sample);
|
||||
}
|
||||
|
||||
void ObjectSampler::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
|
||||
assert(is_created(), "invariant");
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||
ObjectSampler& sampler = instance();
|
||||
ObjectSample* current = sampler._list->last();
|
||||
while (current != NULL) {
|
||||
if (current->_object != NULL) {
|
||||
if (is_alive->do_object_b(current->object_raw())) {
|
||||
// The weakly referenced object is alive, update pointer
|
||||
f->do_oop(const_cast<oop*>(current->object_addr()));
|
||||
} else {
|
||||
// clear existing field to assist GC barriers
|
||||
current->_object = NULL;
|
||||
sampler._dead_samples = true;
|
||||
}
|
||||
}
|
||||
current = current->next();
|
||||
}
|
||||
sampler._last_sweep = JfrTicks::now();
|
||||
}
|
||||
|
||||
ObjectSample* ObjectSampler::last() const {
|
||||
return _list->last();
|
||||
}
|
||||
@ -267,6 +285,6 @@ ObjectSample* ObjectSampler::item_at(int index) {
|
||||
);
|
||||
}
|
||||
|
||||
const JfrTicks& ObjectSampler::last_sweep() const {
|
||||
const JfrTicks& ObjectSampler::last_sweep() {
|
||||
return _last_sweep;
|
||||
}
|
||||
|
@ -30,9 +30,8 @@
|
||||
|
||||
typedef u8 traceid;
|
||||
|
||||
class BoolObjectClosure;
|
||||
class JavaThread;
|
||||
class OopClosure;
|
||||
class OopStorage;
|
||||
class ObjectSample;
|
||||
class SampleList;
|
||||
class SamplePriorityQueue;
|
||||
@ -41,17 +40,17 @@ class SamplePriorityQueue;
|
||||
// making sure the samples are evenly distributed as
|
||||
// new entries are added and removed.
|
||||
class ObjectSampler : public CHeapObj<mtTracing> {
|
||||
friend class JfrRecorder;
|
||||
friend class LeakProfiler;
|
||||
friend class ObjectSample;
|
||||
friend class StartOperation;
|
||||
friend class StopOperation;
|
||||
private:
|
||||
SamplePriorityQueue* _priority_queue;
|
||||
SampleList* _list;
|
||||
JfrTicks _last_sweep;
|
||||
size_t _total_allocated;
|
||||
size_t _threshold;
|
||||
size_t _size;
|
||||
bool _dead_samples;
|
||||
|
||||
// Lifecycle
|
||||
explicit ObjectSampler(size_t size);
|
||||
@ -66,24 +65,26 @@ class ObjectSampler : public CHeapObj<mtTracing> {
|
||||
void scavenge();
|
||||
void remove_dead(ObjectSample* sample);
|
||||
|
||||
// Called by GC
|
||||
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f);
|
||||
|
||||
const ObjectSample* item_at(int index) const;
|
||||
ObjectSample* item_at(int index);
|
||||
int item_count() const;
|
||||
|
||||
// OopStorage
|
||||
static bool create_oop_storage();
|
||||
static OopStorage* oop_storage();
|
||||
// Invoked by the GC post oop storage processing.
|
||||
static void oop_storage_gc_notification(size_t num_dead);
|
||||
|
||||
public:
|
||||
static ObjectSampler* sampler();
|
||||
// For operations that require exclusive access (non-safepoint)
|
||||
static ObjectSampler* acquire();
|
||||
static void release();
|
||||
|
||||
static const JfrTicks& last_sweep();
|
||||
const ObjectSample* first() const;
|
||||
ObjectSample* last() const;
|
||||
const ObjectSample* last_resolved() const;
|
||||
void set_last_resolved(const ObjectSample* sample);
|
||||
const JfrTicks& last_sweep() const;
|
||||
};
|
||||
|
||||
#endif // SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLER_HPP
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "jfr/dcmd/jfrDcmds.hpp"
|
||||
#include "jfr/instrumentation/jfrJvmtiAgent.hpp"
|
||||
#include "jfr/jni/jfrJavaSupport.hpp"
|
||||
#include "jfr/leakprofiler/sampling/objectSampler.hpp"
|
||||
#include "jfr/periodic/jfrOSInterface.hpp"
|
||||
#include "jfr/periodic/sampling/jfrThreadSampler.hpp"
|
||||
#include "jfr/recorder/jfrRecorder.hpp"
|
||||
@ -73,12 +74,20 @@ bool JfrRecorder::is_enabled() {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
bool JfrRecorder::create_oop_storages() {
|
||||
// currently only a single weak oop storage for Leak Profiler
|
||||
return ObjectSampler::create_oop_storage();
|
||||
}
|
||||
|
||||
bool JfrRecorder::on_create_vm_1() {
|
||||
if (!is_disabled()) {
|
||||
if (FlightRecorder || StartFlightRecording != NULL) {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
if (!create_oop_storages()) {
|
||||
return false;
|
||||
}
|
||||
// fast time initialization
|
||||
return JfrTime::initialize();
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ class JfrRecorder : public JfrCHeapObj {
|
||||
static bool create_chunk_repository();
|
||||
static bool create_java_event_writer();
|
||||
static bool create_jvmti_agent();
|
||||
static bool create_oop_storages();
|
||||
static bool create_os_interface();
|
||||
static bool create_post_box();
|
||||
static bool create_recorder_thread();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -58,6 +58,9 @@ class WeakHandle {
|
||||
|
||||
void print() const;
|
||||
void print_on(outputStream* st) const;
|
||||
|
||||
bool is_empty() const { return _obj == NULL; }
|
||||
oop* ptr_raw() const { return _obj; }
|
||||
};
|
||||
|
||||
#endif // SHARE_OOPS_WEAKHANDLE_HPP
|
||||
|
Loading…
x
Reference in New Issue
Block a user