Skip to content

Commit f553819

Browse files
author
Thomas Schatzl
committed
8317007: Add bulk removal of dead nmethods during class unloading
Reviewed-by: ayang, iwalulya
1 parent 34351b7 commit f553819

27 files changed

+151
-65
lines changed

src/hotspot/share/code/codeBlob.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ RuntimeBlob::RuntimeBlob(
164164
void RuntimeBlob::free(RuntimeBlob* blob) {
165165
assert(blob != nullptr, "caller must check for nullptr");
166166
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
167-
blob->purge();
167+
blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
168168
{
169169
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
170170
CodeCache::free(blob);
@@ -173,7 +173,7 @@ void RuntimeBlob::free(RuntimeBlob* blob) {
173173
MemoryService::track_code_cache_memory_usage();
174174
}
175175

176-
void CodeBlob::purge(bool free_code_cache_data) {
176+
void CodeBlob::purge(bool free_code_cache_data, bool unregister_nmethod) {
177177
if (_oop_maps != nullptr) {
178178
delete _oop_maps;
179179
_oop_maps = nullptr;

src/hotspot/share/code/codeBlob.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class CodeBlob {
143143
static unsigned int align_code_offset(int offset);
144144

145145
// Deletion
146-
virtual void purge(bool free_code_cache_data = true);
146+
virtual void purge(bool free_code_cache_data, bool unregister_nmethod);
147147

148148
// Typing
149149
virtual bool is_buffer_blob() const { return false; }

src/hotspot/share/code/compiledMethod.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class CompiledMethod : public CodeBlob {
174174

175175
void* _gc_data;
176176

177-
virtual void purge(bool free_code_cache_data = true) = 0;
177+
virtual void purge(bool free_code_cache_data, bool unregister_nmethod) = 0;
178178

179179
private:
180180
DeoptimizationStatus deoptimization_status() const {

src/hotspot/share/code/nmethod.cpp

+8-6
Original file line numberDiff line numberDiff line change
@@ -1444,7 +1444,9 @@ void nmethod::unlink() {
14441444
ClassUnloadingContext::context()->register_unlinked_nmethod(this);
14451445
}
14461446

1447-
void nmethod::purge(bool free_code_cache_data) {
1447+
void nmethod::purge(bool free_code_cache_data, bool unregister_nmethod) {
1448+
assert(!free_code_cache_data, "must only call not freeing code cache data");
1449+
14481450
MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag);
14491451

14501452
// completely deallocate this method
@@ -1464,13 +1466,13 @@ void nmethod::purge(bool free_code_cache_data) {
14641466
ec = next;
14651467
}
14661468

1467-
Universe::heap()->unregister_nmethod(this);
1469+
if (unregister_nmethod) {
1470+
Universe::heap()->unregister_nmethod(this);
1471+
}
1472+
14681473
CodeCache::unregister_old_nmethod(this);
14691474

1470-
CodeBlob::purge();
1471-
if (free_code_cache_data) {
1472-
CodeCache::free(this);
1473-
}
1475+
CodeBlob::purge(free_code_cache_data, unregister_nmethod);
14741476
}
14751477

14761478
oop nmethod::oop_at(int index) const {

src/hotspot/share/code/nmethod.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ class nmethod : public CompiledMethod {
522522
void unlink();
523523

524524
// Deallocate this nmethod - called by the GC
525-
void purge(bool free_code_cache_data = true);
525+
void purge(bool free_code_cache_data, bool unregister_nmethod);
526526

527527
// See comment at definition of _last_seen_on_stack
528528
void mark_as_maybe_on_stack();

src/hotspot/share/compiler/compileBroker.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1788,7 +1788,7 @@ bool CompileBroker::init_compiler_runtime() {
17881788
void CompileBroker::free_buffer_blob_if_allocated(CompilerThread* thread) {
17891789
BufferBlob* blob = thread->get_buffer_blob();
17901790
if (blob != nullptr) {
1791-
blob->purge();
1791+
blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
17921792
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
17931793
CodeCache::free(blob);
17941794
}

src/hotspot/share/gc/g1/g1CodeRootSet.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,15 @@ class G1CodeRootSetHashTable : public CHeapObj<mtGC> {
187187
}
188188
}
189189

190+
// Removes dead/unlinked entries.
191+
void bulk_remove() {
192+
auto delete_check = [&] (nmethod** value) {
193+
return (*value)->is_unlinked();
194+
};
195+
196+
clean(delete_check);
197+
}
198+
190199
// Calculate the log2 of the table size we want to shrink to.
191200
size_t log2_target_shrink_size(size_t current_size) const {
192201
// A table with the new size should be at most filled by this factor. Otherwise
@@ -255,6 +264,11 @@ bool G1CodeRootSet::remove(nmethod* method) {
255264
return _table->remove(method);
256265
}
257266

267+
void G1CodeRootSet::bulk_remove() {
268+
assert(!_is_iterating, "should not mutate while iterating the table");
269+
_table->bulk_remove();
270+
}
271+
258272
bool G1CodeRootSet::contains(nmethod* method) {
259273
return _table->contains(method);
260274
}

src/hotspot/share/gc/g1/g1CodeRootSet.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class G1CodeRootSet {
4444

4545
void add(nmethod* method);
4646
bool remove(nmethod* method);
47+
void bulk_remove();
4748
bool contains(nmethod* method);
4849
void clear();
4950

src/hotspot/share/gc/g1/g1CollectedHeap.cpp

+34-28
Original file line numberDiff line numberDiff line change
@@ -2517,6 +2517,7 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25172517
GCTraceTime(Debug, gc, phases) debug(description, timer);
25182518

25192519
ClassUnloadingContext ctx(workers()->active_workers(),
2520+
false /* unregister_nmethods_during_purge */,
25202521
false /* lock_codeblob_free_separately */);
25212522
{
25222523
CodeCache::UnlinkingScope scope(is_alive);
@@ -2528,6 +2529,10 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25282529
GCTraceTime(Debug, gc, phases) t("Purge Unlinked NMethods", timer);
25292530
ctx.purge_nmethods();
25302531
}
2532+
{
2533+
GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", timer);
2534+
G1CollectedHeap::heap()->bulk_unregister_nmethods();
2535+
}
25312536
{
25322537
GCTraceTime(Debug, gc, phases) t("Free Code Blobs", timer);
25332538
ctx.free_code_blobs();
@@ -2539,6 +2544,33 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25392544
}
25402545
}
25412546

2547+
class G1BulkUnregisterNMethodTask : public WorkerTask {
2548+
HeapRegionClaimer _hrclaimer;
2549+
2550+
class UnregisterNMethodsHeapRegionClosure : public HeapRegionClosure {
2551+
public:
2552+
2553+
bool do_heap_region(HeapRegion* hr) {
2554+
hr->rem_set()->bulk_remove_code_roots();
2555+
return false;
2556+
}
2557+
} _cl;
2558+
2559+
public:
2560+
G1BulkUnregisterNMethodTask(uint num_workers)
2561+
: WorkerTask("G1 Remove Unlinked NMethods From Code Root Set Task"),
2562+
_hrclaimer(num_workers) { }
2563+
2564+
void work(uint worker_id) {
2565+
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&_cl, &_hrclaimer, worker_id);
2566+
}
2567+
};
2568+
2569+
void G1CollectedHeap::bulk_unregister_nmethods() {
2570+
uint num_workers = workers()->active_workers();
2571+
G1BulkUnregisterNMethodTask t(num_workers);
2572+
workers()->run_task(&t);
2573+
}
25422574

25432575
bool G1STWSubjectToDiscoveryClosure::do_object_b(oop obj) {
25442576
assert(obj != nullptr, "must not be null");
@@ -2963,41 +2995,15 @@ class RegisterNMethodOopClosure: public OopClosure {
29632995
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
29642996
};
29652997

2966-
class UnregisterNMethodOopClosure: public OopClosure {
2967-
G1CollectedHeap* _g1h;
2968-
nmethod* _nm;
2969-
2970-
public:
2971-
UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
2972-
_g1h(g1h), _nm(nm) {}
2973-
2974-
void do_oop(oop* p) {
2975-
oop heap_oop = RawAccess<>::oop_load(p);
2976-
if (!CompressedOops::is_null(heap_oop)) {
2977-
oop obj = CompressedOops::decode_not_null(heap_oop);
2978-
HeapRegion* hr = _g1h->heap_region_containing(obj);
2979-
assert(!hr->is_continues_humongous(),
2980-
"trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT
2981-
" starting at " HR_FORMAT,
2982-
p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()));
2983-
2984-
hr->remove_code_root(_nm);
2985-
}
2986-
}
2987-
2988-
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
2989-
};
2990-
29912998
void G1CollectedHeap::register_nmethod(nmethod* nm) {
29922999
guarantee(nm != nullptr, "sanity");
29933000
RegisterNMethodOopClosure reg_cl(this, nm);
29943001
nm->oops_do(&reg_cl);
29953002
}
29963003

29973004
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
2998-
guarantee(nm != nullptr, "sanity");
2999-
UnregisterNMethodOopClosure reg_cl(this, nm);
3000-
nm->oops_do(&reg_cl, true);
3005+
// We always unregister nmethods in bulk during code unloading only.
3006+
ShouldNotReachHere();
30013007
}
30023008

30033009
void G1CollectedHeap::update_used_after_gc(bool evacuation_failed) {

src/hotspot/share/gc/g1/g1CollectedHeap.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,8 @@ class G1CollectedHeap : public CollectedHeap {
12701270

12711271
void unload_classes_and_code(const char* description, BoolObjectClosure* cl, GCTimer* timer);
12721272

1273+
void bulk_unregister_nmethods();
1274+
12731275
// Verification
12741276

12751277
// Perform any cleanup actions necessary before allowing a verification.

src/hotspot/share/gc/g1/heapRegionRemSet.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ void HeapRegionRemSet::remove_code_root(nmethod* nm) {
115115
guarantee(!_code_roots.contains(nm), "duplicate entry found");
116116
}
117117

118+
void HeapRegionRemSet::bulk_remove_code_roots() {
119+
_code_roots.bulk_remove();
120+
}
121+
118122
void HeapRegionRemSet::code_roots_do(CodeBlobClosure* blk) const {
119123
_code_roots.nmethods_do(blk);
120124
}

src/hotspot/share/gc/g1/heapRegionRemSet.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ class HeapRegionRemSet : public CHeapObj<mtGC> {
150150
// the heap region that owns this RSet.
151151
void add_code_root(nmethod* nm);
152152
void remove_code_root(nmethod* nm);
153+
void bulk_remove_code_roots();
153154

154155
// Applies blk->do_code_blob() to each of the entries in _code_roots
155156
void code_roots_do(CodeBlobClosure* blk) const;

src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,14 @@ void ParallelScavengeHeap::resize_all_tlabs() {
532532
CollectedHeap::resize_all_tlabs();
533533
}
534534

535+
void ParallelScavengeHeap::prune_scavengable_nmethods() {
536+
ScavengableNMethods::prune_nmethods_not_into_young();
537+
}
538+
539+
void ParallelScavengeHeap::prune_unlinked_nmethods() {
540+
ScavengableNMethods::prune_unlinked_nmethods();
541+
}
542+
535543
// This method is used by System.gc() and JVMTI.
536544
void ParallelScavengeHeap::collect(GCCause::Cause cause) {
537545
assert(!Heap_lock->owned_by_self(),
@@ -863,10 +871,6 @@ void ParallelScavengeHeap::verify_nmethod(nmethod* nm) {
863871
ScavengableNMethods::verify_nmethod(nm);
864872
}
865873

866-
void ParallelScavengeHeap::prune_scavengable_nmethods() {
867-
ScavengableNMethods::prune_nmethods();
868-
}
869-
870874
GrowableArray<GCMemoryManager*> ParallelScavengeHeap::memory_managers() {
871875
GrowableArray<GCMemoryManager*> memory_managers(2);
872876
memory_managers.append(_young_manager);

src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ class ParallelScavengeHeap : public CollectedHeap {
176176
void verify_nmethod(nmethod* nm) override;
177177

178178
void prune_scavengable_nmethods();
179+
void prune_unlinked_nmethods();
179180

180181
size_t max_capacity() const override;
181182

src/hotspot/share/gc/parallel/psParallelCompact.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
17691769
ref_processor()->start_discovery(maximum_heap_compaction);
17701770

17711771
ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */,
1772+
false /* unregister_nmethods_during_purge */,
17721773
false /* lock_codeblob_free_separately */);
17731774

17741775
marking_phase(&_gc_tracer);
@@ -2078,6 +2079,10 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
20782079
// Release unloaded nmethod's memory.
20792080
ctx->purge_nmethods();
20802081
}
2082+
{
2083+
GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", &_gc_timer);
2084+
ParallelScavengeHeap::heap()->prune_unlinked_nmethods();
2085+
}
20812086
{
20822087
GCTraceTime(Debug, gc, phases) t("Free Code Blobs", gc_timer());
20832088
ctx->free_code_blobs();

src/hotspot/share/gc/serial/genMarkSweep.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
219219
// Release unloaded nmethod's memory.
220220
ctx->purge_nmethods();
221221
}
222+
{
223+
GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", gc_timer());
224+
gch->prune_unlinked_nmethods();
225+
}
222226
{
223227
GCTraceTime(Debug, gc, phases) t("Free Code Blobs", gc_timer());
224228
ctx->free_code_blobs();

src/hotspot/share/gc/serial/serialHeap.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "gc/serial/tenuredGeneration.inline.hpp"
2929
#include "gc/shared/gcLocker.inline.hpp"
3030
#include "gc/shared/genMemoryPools.hpp"
31+
#include "gc/shared/scavengableNMethods.hpp"
3132
#include "gc/shared/strongRootsScope.hpp"
3233
#include "gc/shared/suspendibleThreadSet.hpp"
3334
#include "memory/universe.hpp"

src/hotspot/share/gc/shared/classUnloadingContext.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@
3232

3333
ClassUnloadingContext* ClassUnloadingContext::_context = nullptr;
3434

35-
ClassUnloadingContext::ClassUnloadingContext(uint num_workers, bool lock_codeblob_free_separately) :
35+
ClassUnloadingContext::ClassUnloadingContext(uint num_workers,
36+
bool unregister_nmethods_during_purge,
37+
bool lock_codeblob_free_separately) :
3638
_cld_head(nullptr),
3739
_num_nmethod_unlink_workers(num_workers),
3840
_unlinked_nmethods(nullptr),
41+
_unregister_nmethods_during_purge(unregister_nmethods_during_purge),
3942
_lock_codeblob_free_separately(lock_codeblob_free_separately) {
4043

4144
assert(_context == nullptr, "context already set");
@@ -113,7 +116,7 @@ void ClassUnloadingContext::purge_nmethods() {
113116
NMethodSet* set = _unlinked_nmethods[i];
114117
for (nmethod* nm : *set) {
115118
freed_memory += nm->size();
116-
nm->purge(false /* free_code_cache_data */);
119+
nm->purge(false /* free_code_cache_data */, _unregister_nmethods_during_purge);
117120
}
118121
}
119122

src/hotspot/share/gc/shared/classUnloadingContext.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,22 @@ class ClassUnloadingContext : public CHeapObj<mtGC> {
4242
using NMethodSet = GrowableArrayCHeap<nmethod*, mtGC>;
4343
NMethodSet** _unlinked_nmethods;
4444

45+
bool _unregister_nmethods_during_purge;
4546
bool _lock_codeblob_free_separately;
4647

4748
public:
4849
static ClassUnloadingContext* context() { assert(_context != nullptr, "context not set"); return _context; }
4950

5051
// Num_nmethod_unlink_workers configures the maximum numbers of threads unlinking
5152
// nmethods.
53+
// unregister_nmethods_during_purge determines whether unloaded nmethods should
54+
// be unregistered from the garbage collector during purge. If not, ,the caller
55+
// is responsible to do that later.
5256
// lock_codeblob_free_separately determines whether freeing the code blobs takes
5357
// the CodeCache_lock during the whole operation (=false) or per code blob
5458
// free operation (=true).
5559
ClassUnloadingContext(uint num_nmethod_unlink_workers,
60+
bool unregister_nmethods_during_purge,
5661
bool lock_codeblob_free_separately);
5762
~ClassUnloadingContext();
5863

src/hotspot/share/gc/shared/genCollectedHeap.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ void GenCollectedHeap::do_collection(bool full,
524524
CodeCache::on_gc_marking_cycle_start();
525525

526526
ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */,
527+
false /* unregister_nmethods_during_purge */,
527528
false /* lock_codeblob_free_separately */);
528529

529530
collect_generation(_old_gen,
@@ -582,7 +583,11 @@ void GenCollectedHeap::verify_nmethod(nmethod* nm) {
582583
}
583584

584585
void GenCollectedHeap::prune_scavengable_nmethods() {
585-
ScavengableNMethods::prune_nmethods();
586+
ScavengableNMethods::prune_nmethods_not_into_young();
587+
}
588+
589+
void GenCollectedHeap::prune_unlinked_nmethods() {
590+
ScavengableNMethods::prune_unlinked_nmethods();
586591
}
587592

588593
HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {

src/hotspot/share/gc/shared/genCollectedHeap.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ class GenCollectedHeap : public CollectedHeap {
182182
void verify_nmethod(nmethod* nm) override;
183183

184184
void prune_scavengable_nmethods();
185+
void prune_unlinked_nmethods();
185186

186187
// Iteration functions.
187188
void object_iterate(ObjectClosure* cl) override;

0 commit comments

Comments
 (0)