Skip to content

Commit c8fab04

Browse files
author
duke
committed
Backport 8ed214f3b1864ea0095d05497f782ce4131836d4
1 parent e58859e commit c8fab04

File tree

7 files changed

+135
-15
lines changed

7 files changed

+135
-15
lines changed

src/hotspot/share/jfr/jfr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ void Jfr::on_resolution(const Method* caller, const Method* target, TRAPS) {
151151
}
152152
#endif
153153

154-
void Jfr::on_vm_shutdown(bool exception_handler, bool halt) {
154+
void Jfr::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt) {
155155
if (!halt && JfrRecorder::is_recording()) {
156-
JfrEmergencyDump::on_vm_shutdown(exception_handler);
156+
JfrEmergencyDump::on_vm_shutdown(emit_old_object_samples, emit_event_shutdown);
157157
}
158158
}
159159

src/hotspot/share/jfr/jfr.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class Jfr : AllStatic {
7070
static void on_resolution(const Method* caller, const Method* target, TRAPS);
7171
static void on_java_thread_start(JavaThread* starter, JavaThread* startee);
7272
static void on_set_current_thread(JavaThread* jt, oop thread);
73-
static void on_vm_shutdown(bool exception_handler = false, bool halt = false);
73+
static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown, bool halt = false);
7474
static void on_vm_error_report(outputStream* st);
7575
static bool on_flight_recorder_option(const JavaVMOption** option, char* delimiter);
7676
static bool on_start_flight_recording_option(const JavaVMOption** option, char* delimiter);

src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -556,22 +556,22 @@ class JavaThreadInVMAndNative : public StackObj {
556556
}
557557
};
558558

559-
static void post_events(bool exception_handler, Thread* thread) {
560-
if (exception_handler) {
559+
static void post_events(bool emit_old_object_samples, bool emit_event_shutdown, Thread* thread) {
560+
if (emit_old_object_samples) {
561+
LeakProfiler::emit_events(max_jlong, false, false);
562+
}
563+
if (emit_event_shutdown) {
561564
EventShutdown e;
562565
e.set_reason("VM Error");
563566
e.commit();
564-
} else {
565-
// OOM
566-
LeakProfiler::emit_events(max_jlong, false, false);
567567
}
568568
EventDumpReason event;
569-
event.set_reason(exception_handler ? "Crash" : "Out of Memory");
569+
event.set_reason(emit_old_object_samples ? "Out of Memory" : "Crash");
570570
event.set_recordingId(-1);
571571
event.commit();
572572
}
573573

574-
void JfrEmergencyDump::on_vm_shutdown(bool exception_handler) {
574+
void JfrEmergencyDump::on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown) {
575575
if (!guard_reentrancy()) {
576576
return;
577577
}
@@ -584,7 +584,7 @@ void JfrEmergencyDump::on_vm_shutdown(bool exception_handler) {
584584
if (!prepare_for_emergency_dump(thread)) {
585585
return;
586586
}
587-
post_events(exception_handler, thread);
587+
post_events(emit_old_object_samples, emit_event_shutdown, thread);
588588
// if JavaThread, transition to _thread_in_native to issue a final flushpoint
589589
NoHandleMark nhm;
590590
jtivm.transition_to_native();

src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -39,7 +39,7 @@ class JfrEmergencyDump : AllStatic {
3939
static const char* chunk_path(const char* repository_path);
4040
static void on_vm_error(const char* repository_path);
4141
static void on_vm_error_report(outputStream* st, const char* repository_path);
42-
static void on_vm_shutdown(bool exception_handler);
42+
static void on_vm_shutdown(bool emit_old_object_samples, bool emit_event_shutdown);
4343
};
4444

4545
#endif // SHARE_JFR_RECORDER_REPOSITORY_JFREMERGENCYDUMP_HPP

src/hotspot/share/runtime/java.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,10 @@ void before_exit(JavaThread* thread, bool halt) {
463463
event.commit();
464464
}
465465

466-
JFR_ONLY(Jfr::on_vm_shutdown(false, halt);)
466+
// 2nd argument (emit_event_shutdown) should be set to false
467+
// because EventShutdown would be emitted at Threads::destroy_vm().
468+
// (one of the callers of before_exit())
469+
JFR_ONLY(Jfr::on_vm_shutdown(true, false, halt);)
467470

468471
// Stop the WatcherThread. We do this before disenrolling various
469472
// PeriodicTasks to reduce the likelihood of races.

src/hotspot/share/utilities/vmError.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1856,7 +1856,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt
18561856
log.set_fd(-1);
18571857
}
18581858

1859-
JFR_ONLY(Jfr::on_vm_shutdown(true);)
1859+
JFR_ONLY(Jfr::on_vm_shutdown(static_cast<VMErrorType>(_id) == OOM_JAVA_HEAP_FATAL, true);)
18601860

18611861
if (PrintNMTStatistics) {
18621862
fdStream fds(fd_out);
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2025, NTT DATA.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation.
9+
*
10+
* This code is distributed in the hope that it will be useful, but WITHOUT
11+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
* version 2 for more details (a copy is included in the LICENSE file that
14+
* accompanied this code).
15+
*
16+
* You should have received a copy of the GNU General Public License version
17+
* 2 along with this work; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*
20+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21+
* or visit www.oracle.com if you need additional information or have any
22+
* questions.
23+
*/
24+
25+
package jdk.jfr.event.oldobject;
26+
27+
import java.nio.file.Files;
28+
import java.nio.file.Path;
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
import java.util.concurrent.atomic.AtomicLong;
32+
import java.util.concurrent.atomic.AtomicReference;
33+
import jdk.jfr.consumer.EventStream;
34+
import jdk.jfr.consumer.RecordingFile;
35+
36+
import jdk.test.lib.Asserts;
37+
import jdk.test.lib.process.OutputAnalyzer;
38+
import jdk.test.lib.process.ProcessTools;
39+
40+
/**
41+
* @test
42+
* @bug 8364090
43+
* @summary Tests Dump reason and OldObjectSample events at OOME.
44+
* @requires vm.flagless
45+
* @requires vm.hasJFR
46+
* @library /test/lib
47+
* @run main/othervm jdk.jfr.event.oldobject.TestEmergencyDumpAtOOM
48+
*/
49+
public class TestEmergencyDumpAtOOM {
50+
51+
public static List<String> DEFAULT_LEAKER_ARGS = List.of(
52+
"-Xmx64m",
53+
"-XX:TLABSize=2k",
54+
"-XX:StartFlightRecording:dumponexit=true,filename=oom.jfr",
55+
Leaker.class.getName()
56+
);
57+
58+
public static class Leaker {
59+
public static void main(String... args) {
60+
List<byte[]> list = new ArrayList<>();
61+
while (true) {
62+
list.add(new byte[1024]);
63+
}
64+
}
65+
}
66+
67+
private static void test(boolean shouldCrash) throws Exception {
68+
List<String> args = new ArrayList<>(DEFAULT_LEAKER_ARGS);
69+
if (shouldCrash) {
70+
args.add(0, "-XX:+CrashOnOutOfMemoryError");
71+
}
72+
73+
while (true) {
74+
Process p = ProcessTools.createTestJavaProcessBuilder(args).start();
75+
p.waitFor();
76+
OutputAnalyzer output = new OutputAnalyzer(p);
77+
if (!output.contains("java.lang.OutOfMemoryError")) {
78+
throw new RuntimeException("OutOfMemoryError did not happen.");
79+
}
80+
81+
// Check recording file
82+
String jfrFileName = shouldCrash ? String.format("hs_err_pid%d.jfr", p.pid()) : "oom.jfr";
83+
Path jfrPath = Path.of(jfrFileName);
84+
Asserts.assertTrue(Files.exists(jfrPath), "No jfr recording file " + jfrFileName + " exists");
85+
86+
// Check events
87+
AtomicLong oldObjects = new AtomicLong();
88+
AtomicReference<String> shutdownReason = new AtomicReference<>();
89+
AtomicReference<String> dumpReason = new AtomicReference<>();
90+
try (EventStream stream = EventStream.openFile(jfrPath)) {
91+
stream.onEvent("jdk.OldObjectSample", e -> oldObjects.incrementAndGet());
92+
stream.onEvent("jdk.Shutdown", e -> shutdownReason.set(e.getString("reason")));
93+
stream.onEvent("jdk.DumpReason", e -> dumpReason.set(e.getString("reason")));
94+
stream.start();
95+
}
96+
97+
// Check OldObjectSample events
98+
if (oldObjects.get() > 0L) {
99+
if (shouldCrash) {
100+
Asserts.assertEquals("VM Error", shutdownReason.get());
101+
Asserts.assertEquals("Out of Memory", dumpReason.get());
102+
} else {
103+
Asserts.assertEquals("No remaining non-daemon Java threads", shutdownReason.get());
104+
}
105+
// Passed this test
106+
return;
107+
}
108+
109+
System.out.println("Could not find OldObjectSample events. Retrying.");
110+
}
111+
}
112+
113+
public static void main(String... args) throws Exception {
114+
test(true);
115+
test(false);
116+
}
117+
}

0 commit comments

Comments
 (0)