23
23
*/
24
24
25
25
#include " precompiled.hpp"
26
+ #include " gc/shared/oopStorage.hpp"
27
+ #include " gc/shared/oopStorageSet.hpp"
26
28
#include " jfr/jfrEvents.hpp"
27
29
#include " jfr/leakprofiler/sampling/objectSample.hpp"
28
30
#include " jfr/leakprofiler/sampling/objectSampler.hpp"
41
43
#include " runtime/safepoint.hpp"
42
44
#include " runtime/thread.hpp"
43
45
46
+ // Timestamp of when the gc last processed the set of sampled objects.
47
+ static JfrTicks _last_sweep;
48
+
49
+ // Condition variable to communicate that some sampled objects have been cleared by the gc
50
+ // and can therefore be removed from the sample priority queue.
51
+ static bool volatile _dead_samples = false ;
52
+
53
+ // The OopStorage instance is used to hold weak references to sampled objects.
54
+ // It is constructed and registered during VM initialization. This is a singleton
55
+ // that persist independent of the state of the ObjectSampler.
56
+ static OopStorage* _oop_storage = NULL ;
57
+
58
+ OopStorage* ObjectSampler::oop_storage () { return _oop_storage; }
59
+
60
+ // Callback invoked by the GC after an iteration over the oop storage
61
+ // that may have cleared dead referents. num_dead is the number of entries
62
+ // already NULL or cleared by the iteration.
63
+ void ObjectSampler::oop_storage_gc_notification (size_t num_dead) {
64
+ if (num_dead != 0 ) {
65
+ // The ObjectSampler instance may have already been cleaned or a new
66
+ // instance was created concurrently. This allows for a small race where cleaning
67
+ // could be done again.
68
+ Atomic::store (&_dead_samples, true );
69
+ _last_sweep = JfrTicks::now ();
70
+ }
71
+ }
72
+
73
+ bool ObjectSampler::create_oop_storage () {
74
+ _oop_storage = OopStorageSet::create_weak (" Weak JFR Old Object Samples" );
75
+ assert (_oop_storage != NULL , " invariant" );
76
+ _oop_storage->register_num_dead_callback (&oop_storage_gc_notification);
77
+ return true ;
78
+ }
79
+
44
80
static ObjectSampler* _instance = NULL ;
45
81
46
82
static ObjectSampler& instance () {
@@ -49,13 +85,14 @@ static ObjectSampler& instance() {
49
85
}
50
86
51
87
ObjectSampler::ObjectSampler (size_t size) :
52
- _priority_queue(new SamplePriorityQueue(size)),
53
- _list(new SampleList(size)),
54
- _last_sweep(JfrTicks::now()),
55
- _total_allocated(0 ),
56
- _threshold(0 ),
57
- _size(size),
58
- _dead_samples(false ) {}
88
+ _priority_queue(new SamplePriorityQueue(size)),
89
+ _list(new SampleList(size)),
90
+ _total_allocated(0 ),
91
+ _threshold(0 ),
92
+ _size(size) {
93
+ _last_sweep = JfrTicks::now ();
94
+ Atomic::store (&_dead_samples, false );
95
+ }
59
96
60
97
ObjectSampler::~ObjectSampler () {
61
98
delete _priority_queue;
@@ -66,6 +103,7 @@ ObjectSampler::~ObjectSampler() {
66
103
67
104
bool ObjectSampler::create (size_t size) {
68
105
assert (SafepointSynchronize::is_at_safepoint (), " invariant" );
106
+ assert (_oop_storage != NULL , " should be already created" );
69
107
assert (_instance == NULL , " invariant" );
70
108
_instance = new ObjectSampler (size);
71
109
return _instance != NULL ;
@@ -92,13 +130,11 @@ void ObjectSampler::destroy() {
92
130
static volatile int _lock = 0 ;
93
131
94
132
ObjectSampler* ObjectSampler::acquire () {
95
- assert (is_created (), " invariant" );
96
133
while (Atomic::cmpxchg (&_lock, 0 , 1 ) == 1 ) {}
97
134
return _instance;
98
135
}
99
136
100
137
void ObjectSampler::release () {
101
- assert (is_created (), " invariant" );
102
138
OrderAccess::fence ();
103
139
_lock = 0 ;
104
140
}
@@ -150,9 +186,11 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, Java
150
186
assert (thread != NULL , " invariant" );
151
187
assert (thread->jfr_thread_local ()->has_thread_blob (), " invariant" );
152
188
153
- if (_dead_samples) {
189
+ if (Atomic::load (&_dead_samples)) {
190
+ // There's a small race where a GC scan might reset this to true, potentially
191
+ // causing a back-to-back scavenge.
192
+ Atomic::store (&_dead_samples, false );
154
193
scavenge ();
155
- assert (!_dead_samples, " invariant" );
156
194
}
157
195
158
196
_total_allocated += allocated;
@@ -199,12 +237,13 @@ void ObjectSampler::scavenge() {
199
237
}
200
238
current = next;
201
239
}
202
- _dead_samples = false ;
203
240
}
204
241
205
242
void ObjectSampler::remove_dead (ObjectSample* sample) {
206
243
assert (sample != NULL , " invariant" );
207
244
assert (sample->is_dead (), " invariant" );
245
+ sample->release ();
246
+
208
247
ObjectSample* const previous = sample->prev ();
209
248
// push span onto previous
210
249
if (previous != NULL ) {
@@ -216,27 +255,6 @@ void ObjectSampler::remove_dead(ObjectSample* sample) {
216
255
_list->release (sample);
217
256
}
218
257
219
- void ObjectSampler::weak_oops_do (BoolObjectClosure* is_alive, OopClosure* f) {
220
- assert (is_created (), " invariant" );
221
- assert (SafepointSynchronize::is_at_safepoint (), " invariant" );
222
- ObjectSampler& sampler = instance ();
223
- ObjectSample* current = sampler._list ->last ();
224
- while (current != NULL ) {
225
- if (current->_object != NULL ) {
226
- if (is_alive->do_object_b (current->object_raw ())) {
227
- // The weakly referenced object is alive, update pointer
228
- f->do_oop (const_cast <oop*>(current->object_addr ()));
229
- } else {
230
- // clear existing field to assist GC barriers
231
- current->_object = NULL ;
232
- sampler._dead_samples = true ;
233
- }
234
- }
235
- current = current->next ();
236
- }
237
- sampler._last_sweep = JfrTicks::now ();
238
- }
239
-
240
258
ObjectSample* ObjectSampler::last () const {
241
259
return _list->last ();
242
260
}
@@ -267,6 +285,6 @@ ObjectSample* ObjectSampler::item_at(int index) {
267
285
);
268
286
}
269
287
270
- const JfrTicks& ObjectSampler::last_sweep () const {
288
+ const JfrTicks& ObjectSampler::last_sweep () {
271
289
return _last_sweep;
272
290
}
0 commit comments