8330215: Trim working set for OldObjectSamples

Reviewed-by: jbachorik, egahlin
This commit is contained in:
Markus Grönlund 2024-04-16 06:51:37 +00:00
parent 2f11afdae9
commit def257727d
4 changed files with 65 additions and 16 deletions
src/hotspot/share/jfr

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