mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-6742 Record resident set size in JVM fatal error log
(cherry picked from commit 5cc72b464b)
This commit is contained in:
@@ -82,6 +82,18 @@
|
||||
#include <signal.h>
|
||||
#endif // PRODUCT
|
||||
|
||||
#ifdef LINUX
|
||||
#include "os_linux.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
#include <psapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
bool VMError::coredump_status;
|
||||
char VMError::coredump_message[O_BUFLEN];
|
||||
int VMError::_current_step;
|
||||
@@ -1271,6 +1283,9 @@ void VMError::report(outputStream* st, bool _verbose) {
|
||||
JNIHandles::print_on_unsafe(st);
|
||||
JNIHandles::print_memory_usage_on(st);
|
||||
|
||||
STEP_IF("Process memory usage", _verbose)
|
||||
print_process_memory_usage(st);
|
||||
|
||||
STEP("OOME stack traces")
|
||||
st->print_cr("OOME stack traces (most recent first):");
|
||||
print_oome_stacks(st);
|
||||
@@ -1462,6 +1477,7 @@ void VMError::print_vm_info(outputStream* st) {
|
||||
NativeHeapTrimmer::print_state(st);
|
||||
st->cr();
|
||||
|
||||
print_process_memory_usage(st);
|
||||
|
||||
// STEP("printing system")
|
||||
st->print_cr("--------------- S Y S T E M ---------------");
|
||||
@@ -2315,3 +2331,72 @@ void VMError::print_dup_classes(outputStream *st) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
static void print_process_memory_usage_platform(outputStream *st)
|
||||
{
|
||||
// See also os::Linux::print_process_memory_info()
|
||||
os::Linux::meminfo_t info;
|
||||
if (os::Linux::query_process_memory_info(&info)) {
|
||||
ssize_t phys_total_kb = os::physical_memory() / K;
|
||||
ssize_t phys_avail_kb = os::available_memory() / K;
|
||||
int rss_percentile = (int)(info.vmrss * 100.0 / phys_total_kb);
|
||||
st->print_cr("Resident Set Size: %zdK (%d%% of "
|
||||
"%zdK total physical memory with %zdK free physical memory)",
|
||||
info.vmrss, rss_percentile, phys_total_kb, phys_avail_kb);
|
||||
} else {
|
||||
st->print_cr("Could not open /proc/self/status to get process memory related information");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WINDOWS
|
||||
static void print_process_memory_usage_platform(outputStream *st)
|
||||
{
|
||||
// See os::jfr_report_memory_info() in os_windows.cpp
|
||||
PROCESS_MEMORY_COUNTERS_EX pmex;
|
||||
ZeroMemory(&pmex, sizeof(PROCESS_MEMORY_COUNTERS_EX));
|
||||
pmex.cb = sizeof(pmex);
|
||||
|
||||
BOOL ret = GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmex, sizeof(pmex));
|
||||
if (ret != 0) {
|
||||
ssize_t rss_kb = pmex.WorkingSetSize / K;
|
||||
ssize_t phys_total_kb = os::physical_memory() / K;
|
||||
ssize_t phys_avail_kb = os::available_memory() / K;
|
||||
int rss_percentile = (int)(rss_kb * 100.0 / phys_total_kb);
|
||||
st->print_cr("Resident Set Size: %zdK (%d%% of "
|
||||
"%zdK total physical memory with %zdK free physical memory)",
|
||||
rss_kb, rss_percentile, phys_total_kb, phys_avail_kb);
|
||||
} else {
|
||||
st->print_cr("GetProcessMemoryInfo() call did not succeed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void print_process_memory_usage_platform(outputStream *st)
|
||||
{
|
||||
// See os::jfr_report_memory_info() in os_bsd.cpp
|
||||
mach_task_basic_info info;
|
||||
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
|
||||
|
||||
kern_return_t ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count);
|
||||
if (ret == KERN_SUCCESS) {
|
||||
ssize_t rss_kb = info.resident_size / K;
|
||||
ssize_t phys_total_kb = os::physical_memory() / K;
|
||||
ssize_t phys_avail_kb = os::available_memory() / K;
|
||||
int rss_percentile = (int)(rss_kb * 100.0 / phys_total_kb);
|
||||
st->print_cr("Resident Set Size: %zdK (%d%% of "
|
||||
"%zdK total physical memory with %zdK free physical memory)",
|
||||
rss_kb, rss_percentile, phys_total_kb, phys_avail_kb);
|
||||
} else {
|
||||
st->print_cr("task_info() call did not succeed");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void VMError::print_process_memory_usage(outputStream *st)
|
||||
{
|
||||
st->print_cr("Process memory usage:");
|
||||
print_process_memory_usage_platform(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
@@ -232,6 +232,7 @@ public:
|
||||
static void print_oome_stacks(outputStream *st);
|
||||
static void print_classloaders_stats(outputStream *st);
|
||||
static void print_dup_classes(outputStream *st);
|
||||
static void print_process_memory_usage(outputStream *st);
|
||||
};
|
||||
|
||||
class VMErrorCallback {
|
||||
|
||||
79
test/jdk/jb/hotspot/RSSInCrashLog.java
Normal file
79
test/jdk/jb/hotspot/RSSInCrashLog.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2024 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Verifies that the HotSpot crash log includes RSS information.
|
||||
* @library /test/lib
|
||||
* @run main RSSInCrashLog
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RSSInCrashLog {
|
||||
public static void main(String args[]) throws Exception {
|
||||
if (args.length > 0 && args[0].equals("--test")) {
|
||||
System.out.println("Proceeding to crash JVM with OOME");
|
||||
crashJVM();
|
||||
System.out.println("...shouldn't reach here");
|
||||
} else {
|
||||
generateAndVerifyCrashLogContents();
|
||||
}
|
||||
}
|
||||
|
||||
static void crashJVM() {
|
||||
System.out.println("------- first attempt to crash -------");
|
||||
long[][][] array = new long[100][][];
|
||||
for (int i = 0; i < 100; i++) {
|
||||
System.out.println("------- crash attempt #" + i + "-------");
|
||||
array[i] = new long[1000][1000];
|
||||
}
|
||||
int random = (int) (Math.random() * 100);
|
||||
|
||||
System.out.println(array[random][42][0]);
|
||||
}
|
||||
|
||||
public static void generateAndVerifyCrashLogContents() throws Exception {
|
||||
ArrayList<String> opts = new ArrayList<>();
|
||||
opts.add("-Xmx20m");
|
||||
opts.add("-XX:-CreateCoredumpOnCrash");
|
||||
opts.add("-XX:+CrashOnOutOfMemoryError");
|
||||
opts.add("-XX:+ErrorFileToStdout");
|
||||
opts.add(RSSInCrashLog.class.getName());
|
||||
opts.add("--test");
|
||||
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(opts);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.outputTo(System.out);
|
||||
output.shouldContain("Process memory usage");
|
||||
output.shouldContain("Resident Set Size: ");
|
||||
|
||||
Optional<String> rssLine = output.asLines().stream().filter(it -> it.startsWith("Resident Set Size:")).findAny();
|
||||
String rssValue = rssLine.get().split(" ")[3];
|
||||
if (!rssValue.endsWith("K")) {
|
||||
throw new RuntimeException("RSS '" + rssValue + "' does not end with 'K'");
|
||||
}
|
||||
rssValue = rssValue.substring(0, rssValue.length() - 1);
|
||||
long rss = Long.parseLong(rssValue);
|
||||
System.out.println("Parsed RSS: " + rss);
|
||||
if (rss < 10) {
|
||||
throw new RuntimeException("RSS is unusually small: " + rss + "K");
|
||||
}
|
||||
}
|
||||
}
|
||||
64
test/jdk/jb/hotspot/RSSInVmInfo.java
Normal file
64
test/jdk/jb/hotspot/RSSInVmInfo.java
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2024 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Verifies that the VM.info jcmd includes RSS information.
|
||||
* @library /test/lib
|
||||
* @run main/othervm RSSInVmInfo
|
||||
*/
|
||||
|
||||
import jdk.test.lib.JDKToolFinder;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
public class RSSInVmInfo {
|
||||
public static void main(String args[]) throws Exception {
|
||||
long pid = ProcessHandle.current().pid();
|
||||
final OutputAnalyzer output = runJCmd(pid);
|
||||
output.outputTo(System.out);
|
||||
output.shouldContain("Process memory usage");
|
||||
output.shouldContain("Resident Set Size: ");
|
||||
|
||||
Optional<String> rssLine = output.asLines().stream().filter(it -> it.startsWith("Resident Set Size:")).findAny();
|
||||
String rssValue = rssLine.get().split(" ")[3];
|
||||
if (!rssValue.endsWith("K")) {
|
||||
throw new RuntimeException("RSS '" + rssValue + "' does not end with 'K'");
|
||||
}
|
||||
rssValue = rssValue.substring(0, rssValue.length() - 1);
|
||||
long rss = Long.parseLong(rssValue);
|
||||
System.out.println("Parsed RSS: " + rss);
|
||||
if (rss < 10) {
|
||||
throw new RuntimeException("RSS is unusually small: " + rss + "K");
|
||||
}
|
||||
}
|
||||
|
||||
static OutputAnalyzer runJCmd(long pid) {
|
||||
try {
|
||||
final String jcmd = JDKToolFinder.getTestJDKTool("jcmd");
|
||||
final ProcessBuilder pb = new ProcessBuilder(jcmd, String.valueOf(pid), "VM.info");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.outputTo(System.out);
|
||||
output.shouldHaveExitValue(0);
|
||||
return output;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Launching jcmd failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user