8330215: Trim working set for OldObjectSamples
Reviewed-by: jbachorik, egahlin
This commit is contained in:
parent
2f11afdae9
commit
def257727d
src/hotspot/share/jfr
leakprofiler
utilities
@ -264,12 +264,12 @@ void StackTraceBlobInstaller::install(ObjectSample* sample) {
|
||||
static void install_stack_traces(const ObjectSampler* sampler) {
|
||||
assert(sampler != nullptr, "invariant");
|
||||
const ObjectSample* const last = sampler->last();
|
||||
if (last != sampler->last_resolved()) {
|
||||
ResourceMark rm;
|
||||
JfrKlassUnloading::sort();
|
||||
StackTraceBlobInstaller installer;
|
||||
iterate_samples(installer);
|
||||
}
|
||||
assert(last != nullptr, "invariant");
|
||||
assert(last != sampler->last_resolved(), "invariant");
|
||||
ResourceMark rm;
|
||||
JfrKlassUnloading::sort();
|
||||
StackTraceBlobInstaller installer;
|
||||
iterate_samples(installer);
|
||||
}
|
||||
|
||||
void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler) {
|
||||
@ -277,6 +277,9 @@ void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler) {
|
||||
assert(LeakProfiler::is_running(), "invariant");
|
||||
JavaThread* const thread = JavaThread::current();
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(thread);)
|
||||
if (!ObjectSampler::has_unresolved_entry()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
// can safepoint here
|
||||
ThreadInVMfromNative transition(thread);
|
||||
@ -422,8 +425,10 @@ class BlobInstaller {
|
||||
};
|
||||
|
||||
static void install_type_set_blobs() {
|
||||
BlobInstaller installer;
|
||||
iterate_samples(installer);
|
||||
if (saved_type_set_blobs.valid()) {
|
||||
BlobInstaller installer;
|
||||
iterate_samples(installer);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_type_set_blob(JfrCheckpointWriter& writer) {
|
||||
@ -436,20 +441,29 @@ static void save_type_set_blob(JfrCheckpointWriter& writer) {
|
||||
}
|
||||
}
|
||||
|
||||
// This routine has exclusive access to the sampler instance on entry.
|
||||
void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
|
||||
assert(LeakProfiler::is_running(), "invariant");
|
||||
DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(JavaThread::current());)
|
||||
const ObjectSample* last = ObjectSampler::sampler()->last();
|
||||
if (writer.has_data() && last != nullptr) {
|
||||
save_type_set_blob(writer);
|
||||
install_type_set_blobs();
|
||||
ObjectSampler::sampler()->set_last_resolved(last);
|
||||
assert(ClassLoaderDataGraph_lock->owned_by_self(), "invariant");
|
||||
if (!ObjectSampler::has_unresolved_entry()) {
|
||||
return;
|
||||
}
|
||||
const ObjectSample* const last = ObjectSampler::sampler()->last();
|
||||
assert(last != nullptr, "invariant");
|
||||
assert(last != ObjectSampler::sampler()->last_resolved(), "invariant");
|
||||
if (writer.has_data()) {
|
||||
save_type_set_blob(writer);
|
||||
}
|
||||
install_type_set_blobs();
|
||||
ObjectSampler::sampler()->set_last_resolved(last);
|
||||
}
|
||||
|
||||
// This routine does NOT have exclusive access to the sampler instance on entry.
|
||||
void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
|
||||
assert(LeakProfiler::is_running(), "invariant");
|
||||
if (writer.has_data() && ObjectSampler::sampler()->last() != nullptr) {
|
||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||
if (writer.has_data() && ObjectSampler::has_unresolved_entry()) {
|
||||
save_type_set_blob(writer);
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "jfr/recorder/jfrEventSetting.inline.hpp"
|
||||
#include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
|
||||
#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
|
||||
#include "jfr/utilities/jfrSignal.hpp"
|
||||
#include "jfr/support/jfrThreadLocal.hpp"
|
||||
#include "jfr/utilities/jfrTime.hpp"
|
||||
#include "jfr/utilities/jfrTryLock.hpp"
|
||||
@ -59,6 +60,25 @@ static bool volatile _dead_samples = false;
|
||||
// that persist independent of the state of the ObjectSampler.
|
||||
static OopStorage* _oop_storage = nullptr;
|
||||
|
||||
// A notification mechanism to let class unloading determine if to save unloaded typesets.
|
||||
static JfrSignal _unresolved_entry;
|
||||
|
||||
static inline void signal_unresolved_entry() {
|
||||
_unresolved_entry.signal_if_not_set();
|
||||
}
|
||||
|
||||
static inline void clear_unresolved_entry() {
|
||||
_unresolved_entry.reset();
|
||||
}
|
||||
|
||||
static inline void signal_resolved() {
|
||||
clear_unresolved_entry();
|
||||
}
|
||||
|
||||
bool ObjectSampler::has_unresolved_entry() {
|
||||
return _unresolved_entry.is_signaled();
|
||||
}
|
||||
|
||||
OopStorage* ObjectSampler::oop_storage() { return _oop_storage; }
|
||||
|
||||
// Callback invoked by the GC after an iteration over the oop storage
|
||||
@ -108,6 +128,8 @@ ObjectSampler::~ObjectSampler() {
|
||||
bool ObjectSampler::create(size_t size) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||
assert(_oop_storage != nullptr, "should be already created");
|
||||
clear_unresolved_entry();
|
||||
assert(!has_unresolved_entry(), "invariant");
|
||||
ObjectSampleCheckpoint::clear();
|
||||
assert(_instance == nullptr, "invariant");
|
||||
_instance = new ObjectSampler(size);
|
||||
@ -242,6 +264,7 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, bool
|
||||
}
|
||||
|
||||
assert(sample != nullptr, "invariant");
|
||||
signal_unresolved_entry();
|
||||
sample->set_thread_id(thread_id);
|
||||
if (virtual_thread) {
|
||||
sample->set_thread_is_virtual();
|
||||
@ -304,6 +327,7 @@ const ObjectSample* ObjectSampler::last_resolved() const {
|
||||
|
||||
void ObjectSampler::set_last_resolved(const ObjectSample* sample) {
|
||||
_list->set_last_resolved(sample);
|
||||
signal_resolved();
|
||||
}
|
||||
|
||||
int ObjectSampler::item_count() const {
|
||||
|
@ -85,6 +85,7 @@ class ObjectSampler : public CHeapObj<mtTracing> {
|
||||
ObjectSample* last() const;
|
||||
const ObjectSample* last_resolved() const;
|
||||
void set_last_resolved(const ObjectSample* sample);
|
||||
static bool has_unresolved_entry();
|
||||
};
|
||||
|
||||
#endif // SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLER_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2024, 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
|
||||
@ -37,13 +37,23 @@ class JfrSignal {
|
||||
Atomic::release_store(&_signaled, true);
|
||||
}
|
||||
|
||||
void reset() const {
|
||||
Atomic::release_store(&_signaled, false);
|
||||
}
|
||||
|
||||
bool is_signaled() const {
|
||||
return Atomic::load_acquire(&_signaled);
|
||||
}
|
||||
|
||||
void signal_if_not_set() const {
|
||||
if (!is_signaled()) {
|
||||
signal();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_signaled_with_reset() const {
|
||||
if (is_signaled()) {
|
||||
Atomic::release_store(&_signaled, false);
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user