mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-13 04:27:53 +00:00
8387742: Reclaim CodeCache nmethods more promptly
Reviewed-by: tschatzl, shade
This commit is contained in:
parent
3354ad3b6f
commit
3e2366e7f5
@ -868,7 +868,7 @@ void G1CollectedHeap::prepare_for_mutator_after_full_collection(size_t allocatio
|
||||
|
||||
// Rebuild the code root lists for each region
|
||||
rebuild_code_roots();
|
||||
finish_codecache_marking_cycle();
|
||||
CodeCache::arm_all_nmethods();
|
||||
|
||||
start_new_collection_set();
|
||||
_allocator->init_mutator_alloc_regions();
|
||||
@ -3342,8 +3342,3 @@ void G1CollectedHeap::start_codecache_marking_cycle_if_inactive(bool concurrent_
|
||||
CodeCache::arm_all_nmethods();
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::finish_codecache_marking_cycle() {
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
CodeCache::arm_all_nmethods();
|
||||
}
|
||||
|
||||
@ -953,7 +953,6 @@ public:
|
||||
void fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) override;
|
||||
|
||||
static void start_codecache_marking_cycle_if_inactive(bool concurrent_mark_start);
|
||||
static void finish_codecache_marking_cycle();
|
||||
|
||||
// The shared block offset table array.
|
||||
G1BlockOffsetTable* bot() const { return _bot; }
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "classfile/classLoaderDataGraph.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "cppstdlib/new.hpp"
|
||||
#include "gc/g1/g1BarrierSet.hpp"
|
||||
#include "gc/g1/g1BatchedTask.hpp"
|
||||
@ -1378,6 +1379,8 @@ void G1ConcurrentMark::remark() {
|
||||
if (mark_finished) {
|
||||
weak_refs_work();
|
||||
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
|
||||
// Unload Klasses, String, Code Cache, etc.
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
G1CMIsAliveClosure is_alive(this);
|
||||
@ -1446,7 +1449,7 @@ void G1ConcurrentMark::remark() {
|
||||
// Completely reset the marking state (except bitmaps) since marking completed.
|
||||
reset_at_marking_complete();
|
||||
|
||||
G1CollectedHeap::finish_codecache_marking_cycle();
|
||||
CodeCache::arm_all_nmethods();
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) debug("Report Object Count", _gc_timer_cm);
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "classfile/classLoaderDataGraph.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "cppstdlib/new.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
#include "gc/g1/g1FullCollector.inline.hpp"
|
||||
@ -330,6 +331,8 @@ void G1FullCollector::phase1_mark_live_objects() {
|
||||
assert(marker(0)->task_queue()->is_empty(), "Should be no oops on the stack");
|
||||
}
|
||||
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: Flush Mark Stats Cache", scope()->timer());
|
||||
for (uint i = 0; i < workers(); i++) {
|
||||
|
||||
@ -644,7 +644,6 @@ void PSParallelCompact::post_compact()
|
||||
GCTraceTime(Info, gc, phases) tm("Post Compact", &_gc_timer);
|
||||
ParCompactionManager::remove_all_shadow_regions();
|
||||
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
CodeCache::arm_all_nmethods();
|
||||
|
||||
// Need to clear claim bits for the next full-gc (marking and adjust-pointers).
|
||||
@ -1216,6 +1215,7 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
|
||||
|
||||
// This is the point where the entire marking should have completed.
|
||||
ParCompactionManager::verify_all_marking_stack_empty();
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) tm("Weak Processing", &_gc_timer);
|
||||
|
||||
@ -512,6 +512,7 @@ void SerialFullGC::phase1_mark(bool clear_all_softrefs) {
|
||||
|
||||
// This is the point where the entire marking should have completed.
|
||||
assert(_marking_stack.is_empty(), "Marking should have completed");
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) tm_m("Weak Processing", gc_timer());
|
||||
|
||||
@ -589,7 +589,6 @@ void SerialHeap::do_full_collection(bool clear_all_soft_refs) {
|
||||
gc_timer->register_gc_end();
|
||||
|
||||
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
CodeCache::arm_all_nmethods();
|
||||
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
|
||||
|
||||
|
||||
177
test/hotspot/jtreg/gc/TestCodeCacheUnload.java
Normal file
177
test/hotspot/jtreg/gc/TestCodeCacheUnload.java
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package gc;
|
||||
|
||||
/*
|
||||
* @test id=serial
|
||||
* @summary Tests that one full GC unloads a freshly not-entrant nmethod.
|
||||
* @requires vm.gc.Serial
|
||||
* @requires vm.compiler1.enabled
|
||||
* @requires vm.opt.ClassUnloading != false
|
||||
* @requires vm.opt.MethodFlushing != false
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -Xbatch -XX:-BackgroundCompilation
|
||||
* -XX:+UseSerialGC gc.TestCodeCacheUnload
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=parallel
|
||||
* @summary Tests that one full GC unloads a freshly not-entrant nmethod.
|
||||
* @requires vm.gc.Parallel
|
||||
* @requires vm.compiler1.enabled
|
||||
* @requires vm.opt.ClassUnloading != false
|
||||
* @requires vm.opt.MethodFlushing != false
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -Xbatch -XX:-BackgroundCompilation
|
||||
* -XX:+UseParallelGC gc.TestCodeCacheUnload
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=g1
|
||||
* @summary Tests that one full GC unloads a freshly not-entrant nmethod.
|
||||
* @requires vm.gc.G1
|
||||
* @requires vm.compiler1.enabled
|
||||
* @requires vm.opt.ClassUnloading != false
|
||||
* @requires vm.opt.MethodFlushing != false
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -Xbatch -XX:-BackgroundCompilation
|
||||
* -XX:+UseG1GC gc.TestCodeCacheUnload
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=shenandoah
|
||||
* @summary Tests that one full GC unloads a freshly not-entrant nmethod.
|
||||
* @requires vm.gc.Shenandoah
|
||||
* @requires vm.compiler1.enabled
|
||||
* @requires vm.opt.ClassUnloading != false
|
||||
* @requires vm.opt.MethodFlushing != false
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -Xbatch -XX:-BackgroundCompilation
|
||||
* -XX:+UseShenandoahGC gc.TestCodeCacheUnload
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test id=z
|
||||
* @summary Tests that one full GC unloads a freshly not-entrant nmethod.
|
||||
* @requires vm.gc.Z
|
||||
* @requires vm.compiler1.enabled
|
||||
* @requires vm.opt.ClassUnloading != false
|
||||
* @requires vm.opt.MethodFlushing != false
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -Xbatch -XX:-BackgroundCompilation
|
||||
* -XX:+UseZGC gc.TestCodeCacheUnload
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import jdk.test.lib.dcmd.JMXExecutor;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
|
||||
public class TestCodeCacheUnload {
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
public static class Target {
|
||||
public static int test(int value) {
|
||||
return value + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void compileAndMakeNotEntrant() throws Exception {
|
||||
Method method = Target.class.getDeclaredMethod("test", int.class);
|
||||
|
||||
method.invoke(null, 1);
|
||||
if (!WB.enqueueMethodForCompilation(method, 1 /* compLevel */)) {
|
||||
throw new AssertionError("Failed to enqueue target for compilation");
|
||||
}
|
||||
while (WB.isMethodQueuedForCompilation(method)) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
if (!WB.isMethodCompiled(method)) {
|
||||
throw new AssertionError("Target is not compiled");
|
||||
}
|
||||
|
||||
int deoptimized = WB.deoptimizeMethod(method);
|
||||
if (deoptimized == 0) {
|
||||
throw new AssertionError("No target nmethod was made not-entrant");
|
||||
}
|
||||
}
|
||||
|
||||
private static int countNotEntrantEntries() {
|
||||
OutputAnalyzer output = new JMXExecutor().execute("Compiler.codelist");
|
||||
String target = "gc.TestCodeCacheUnload$Target.test";
|
||||
int result = 0;
|
||||
|
||||
for (String line : output.asLines()) {
|
||||
if (!line.contains(target)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println("Found codelist entry: " + line);
|
||||
String[] parts = line.trim().split("\\s+");
|
||||
int codeState = Integer.parseInt(parts[2]);
|
||||
if (codeState == 1 /* not_entrant */) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
compileAndMakeNotEntrant();
|
||||
WB.fullGC();
|
||||
|
||||
int notEntrantEntries = countNotEntrantEntries();
|
||||
System.out.println("Target not-entrant entries after 1 full GC: " + notEntrantEntries);
|
||||
if (notEntrantEntries != 0) {
|
||||
throw new AssertionError("Expected one full GC to unload the not-entrant nmethod");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package gc.g1;
|
||||
|
||||
/*
|
||||
* @test TestCodeCacheUnloadDuringConcurrentMark
|
||||
* @summary Tests that G1 concurrent marking unloads a freshly not-entrant nmethod.
|
||||
* @requires vm.gc.G1
|
||||
* @requires vm.compiler1.enabled
|
||||
* @requires vm.opt.ClassUnloading != false
|
||||
* @requires vm.opt.ClassUnloadingWithConcurrentMark != false
|
||||
* @requires vm.opt.MethodFlushing != false
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -Xbatch -XX:-BackgroundCompilation
|
||||
* -XX:+UseG1GC
|
||||
* -XX:+ClassUnloadingWithConcurrentMark
|
||||
* gc.g1.TestCodeCacheUnloadDuringConcurrentMark
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import jdk.test.lib.dcmd.JMXExecutor;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
|
||||
public class TestCodeCacheUnloadDuringConcurrentMark {
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
static class Target {
|
||||
public static int test(int value) {
|
||||
return value + 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void compileAndMakeNotEntrant(Method method) throws Exception {
|
||||
Target.test(1);
|
||||
if (!WB.enqueueMethodForCompilation(method, 1 /* compLevel */)) {
|
||||
throw new AssertionError("Failed to enqueue target for compilation");
|
||||
}
|
||||
while (WB.isMethodQueuedForCompilation(method)) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
if (!WB.isMethodCompiled(method)) {
|
||||
throw new AssertionError("Target is not compiled");
|
||||
}
|
||||
|
||||
int deoptimized = WB.deoptimizeMethod(method);
|
||||
if (deoptimized == 0) {
|
||||
throw new AssertionError("No target nmethod was made not-entrant");
|
||||
}
|
||||
}
|
||||
|
||||
private static int countNotEntrantEntries() {
|
||||
String target = TestCodeCacheUnloadDuringConcurrentMark.class.getName() + "$Target.test";
|
||||
int result = 0;
|
||||
|
||||
for (String line : new JMXExecutor().execute("Compiler.codelist", true).asLines()) {
|
||||
if (!line.contains(target)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println("Found codelist entry: " + line);
|
||||
String[] parts = line.trim().split("\\s+");
|
||||
int codeState = Integer.parseInt(parts[2]);
|
||||
if (codeState == 1 /* not_entrant */) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
compileAndMakeNotEntrant(Target.class.getDeclaredMethod("test", int.class));
|
||||
|
||||
int notEntrantEntries = countNotEntrantEntries();
|
||||
System.out.println("Target not-entrant entries before concurrent mark: " + notEntrantEntries);
|
||||
if (notEntrantEntries == 0) {
|
||||
throw new AssertionError("Expected a not-entrant target nmethod before concurrent mark");
|
||||
}
|
||||
|
||||
WB.g1RunConcurrentGC();
|
||||
|
||||
notEntrantEntries = countNotEntrantEntries();
|
||||
System.out.println("Target not-entrant entries after concurrent mark: " + notEntrantEntries);
|
||||
if (notEntrantEntries != 0) {
|
||||
throw new AssertionError("Expected concurrent mark to unload the not-entrant target nmethod");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user