mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-09 23:50:22 +00:00
8379230: JFR: Do not store leak context edge idx in markWord
Reviewed-by: egahlin
This commit is contained in:
parent
ca479be747
commit
45fc141d29
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2026, 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
|
||||
@ -26,8 +26,10 @@
|
||||
#include "jfr/leakprofiler/chains/edgeUtils.hpp"
|
||||
#include "jfr/leakprofiler/sampling/objectSample.hpp"
|
||||
#include "jfr/leakprofiler/utilities/unifiedOopRef.inline.hpp"
|
||||
#include "jfr/recorder/service/jfrOptionSet.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "runtime/safepoint.hpp"
|
||||
#include "utilities/resizableHashTable.hpp"
|
||||
|
||||
StoredEdge::StoredEdge(const Edge* parent, UnifiedOopRef reference) : Edge(parent, reference), _gc_root_id(0), _skip_length(0) {}
|
||||
|
||||
@ -216,84 +218,62 @@ bool EdgeStore::put_edges(StoredEdge** previous, const Edge** current, size_t li
|
||||
return nullptr == *current;
|
||||
}
|
||||
|
||||
static GrowableArray<const StoredEdge*>* _leak_context_edges = nullptr;
|
||||
typedef ResizeableHashTable<uintptr_t, const StoredEdge*, AnyObj::C_HEAP, mtTracing> SampleToLeakContextEdgeMap;
|
||||
static SampleToLeakContextEdgeMap* _sample_to_leak_context_edge_map = nullptr;
|
||||
|
||||
EdgeStore::EdgeStore() : _edges(new EdgeHashTable(this)) {}
|
||||
|
||||
EdgeStore::~EdgeStore() {
|
||||
assert(_edges != nullptr, "invariant");
|
||||
delete _edges;
|
||||
delete _leak_context_edges;
|
||||
_leak_context_edges = nullptr;
|
||||
delete _sample_to_leak_context_edge_map;
|
||||
_sample_to_leak_context_edge_map = nullptr;
|
||||
}
|
||||
|
||||
static int leak_context_edge_idx(const ObjectSample* sample) {
|
||||
static const StoredEdge* leak_context_edge(const ObjectSample* sample) {
|
||||
assert(sample != nullptr, "invariant");
|
||||
return static_cast<int>(sample->object()->mark().value()) >> markWord::lock_bits;
|
||||
assert(_sample_to_leak_context_edge_map != nullptr, "invariant");
|
||||
const StoredEdge** edge = _sample_to_leak_context_edge_map->get(p2u(sample->object()));
|
||||
return edge != nullptr ? *edge : nullptr;
|
||||
}
|
||||
|
||||
bool EdgeStore::has_leak_context(const ObjectSample* sample) const {
|
||||
const int idx = leak_context_edge_idx(sample);
|
||||
if (idx == 0) {
|
||||
return false;
|
||||
}
|
||||
assert(idx > 0, "invariant");
|
||||
assert(_leak_context_edges != nullptr, "invariant");
|
||||
assert(idx < _leak_context_edges->length(), "invariant");
|
||||
assert(_leak_context_edges->at(idx) != nullptr, "invariant");
|
||||
return true;
|
||||
return _sample_to_leak_context_edge_map != nullptr && leak_context_edge(sample) != nullptr;
|
||||
}
|
||||
|
||||
const StoredEdge* EdgeStore::get(const ObjectSample* sample) const {
|
||||
assert(sample != nullptr, "invariant");
|
||||
if (_leak_context_edges != nullptr) {
|
||||
if (_sample_to_leak_context_edge_map != nullptr) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "invariant");
|
||||
const int idx = leak_context_edge_idx(sample);
|
||||
if (idx > 0) {
|
||||
assert(idx < _leak_context_edges->length(), "invariant");
|
||||
const StoredEdge* const edge =_leak_context_edges->at(idx);
|
||||
assert(edge != nullptr, "invariant");
|
||||
const StoredEdge* const edge = leak_context_edge(sample);
|
||||
if (edge != nullptr) {
|
||||
return edge;
|
||||
}
|
||||
}
|
||||
return get(UnifiedOopRef::encode_in_native(sample->object_addr()));
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
// max_idx to ensure idx fit in lower 32-bits of markword together with lock bits.
|
||||
static constexpr const int max_idx = right_n_bits(32 - markWord::lock_bits);
|
||||
static constexpr const unsigned max_map_size = max_jint >> 1;
|
||||
|
||||
static void store_idx_precondition(oop sample_object, int idx) {
|
||||
assert(sample_object != nullptr, "invariant");
|
||||
assert(sample_object->mark().is_marked(), "invariant");
|
||||
assert(idx > 0, "invariant");
|
||||
assert(idx <= max_idx, "invariant");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void store_idx_in_markword(oop sample_object, int idx) {
|
||||
DEBUG_ONLY(store_idx_precondition(sample_object, idx);)
|
||||
const markWord idx_mark_word(sample_object->mark().value() | idx << markWord::lock_bits);
|
||||
sample_object->set_mark(idx_mark_word);
|
||||
assert(sample_object->mark().is_marked(), "must still be marked");
|
||||
}
|
||||
|
||||
static const int initial_size = 64;
|
||||
|
||||
static int save(const StoredEdge* edge) {
|
||||
assert(edge != nullptr, "invariant");
|
||||
if (_leak_context_edges == nullptr) {
|
||||
_leak_context_edges = new (mtTracing) GrowableArray<const StoredEdge*>(initial_size, mtTracing);
|
||||
_leak_context_edges->append(nullptr); // next idx now at 1, for disambiguation in markword.
|
||||
static inline unsigned map_size() {
|
||||
assert(JfrOptionSet::old_object_queue_size() > 0, "invariant");
|
||||
unsigned size = JfrOptionSet::old_object_queue_size();
|
||||
size = round_up_power_of_2(size);
|
||||
if (size < 1024) {
|
||||
return 1024;
|
||||
}
|
||||
return _leak_context_edges->append(edge);
|
||||
size <<= 1;
|
||||
return size >= max_map_size ? max_map_size : size;
|
||||
}
|
||||
|
||||
// We associate the leak context edge with the leak candidate object by saving the
|
||||
// edge in an array and storing the array idx (shifted) into the markword of the candidate object.
|
||||
static void associate_with_candidate(const StoredEdge* leak_context_edge) {
|
||||
assert(leak_context_edge != nullptr, "invariant");
|
||||
store_idx_in_markword(leak_context_edge->pointee(), save(leak_context_edge));
|
||||
if (_sample_to_leak_context_edge_map == nullptr) {
|
||||
const unsigned size = map_size();
|
||||
_sample_to_leak_context_edge_map = new (mtTracing) SampleToLeakContextEdgeMap(size, size);
|
||||
}
|
||||
assert(_sample_to_leak_context_edge_map != nullptr, "invariant");
|
||||
_sample_to_leak_context_edge_map->put(p2u(leak_context_edge->pointee()), leak_context_edge);
|
||||
}
|
||||
|
||||
StoredEdge* EdgeStore::associate_leak_context_with_candidate(const Edge* edge) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2026, 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
|
||||
@ -39,7 +39,6 @@ class StoredEdge : public Edge {
|
||||
size_t _skip_length;
|
||||
|
||||
public:
|
||||
StoredEdge();
|
||||
StoredEdge(const Edge* parent, UnifiedOopRef reference);
|
||||
StoredEdge(const Edge& edge);
|
||||
StoredEdge(const StoredEdge& edge);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user