mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
6302804: Hotspot VM dies ungraceful death when C heap is exhausted in various places
Enhance the error reporting mechanism to help user to fix the problem rather than making it look like a VM error. Reviewed-by: kvn, kamg
This commit is contained in:
parent
dd59086fcc
commit
dec384330b
6 changed files with 71 additions and 23 deletions
|
@ -585,6 +585,13 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_
|
||||||
sigaddset(&newset, sig);
|
sigaddset(&newset, sig);
|
||||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||||
|
|
||||||
|
// Determine which sort of error to throw. Out of swap may signal
|
||||||
|
// on the thread stack, which could get a mapping error when touched.
|
||||||
|
address addr = (address) info->si_addr;
|
||||||
|
if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
|
||||||
|
vm_exit_out_of_memory(0, "Out of swap space to map in thread stack.");
|
||||||
|
}
|
||||||
|
|
||||||
VMError err(t, sig, pc, info, ucVoid);
|
VMError err(t, sig, pc, info, ucVoid);
|
||||||
err.report_and_die();
|
err.report_and_die();
|
||||||
|
|
||||||
|
|
|
@ -742,6 +742,13 @@ int JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid, int abort_
|
||||||
sigaddset(&newset, sig);
|
sigaddset(&newset, sig);
|
||||||
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
sigprocmask(SIG_UNBLOCK, &newset, NULL);
|
||||||
|
|
||||||
|
// Determine which sort of error to throw. Out of swap may signal
|
||||||
|
// on the thread stack, which could get a mapping error when touched.
|
||||||
|
address addr = (address) info->si_addr;
|
||||||
|
if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
|
||||||
|
vm_exit_out_of_memory(0, "Out of swap space to map in thread stack.");
|
||||||
|
}
|
||||||
|
|
||||||
VMError err(t, sig, pc, info, ucVoid);
|
VMError err(t, sig, pc, info, ucVoid);
|
||||||
err.report_and_die();
|
err.report_and_die();
|
||||||
|
|
||||||
|
|
|
@ -2297,14 +2297,15 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
|
||||||
} else if (match_option(option, "-Xoss", &tail)) {
|
} else if (match_option(option, "-Xoss", &tail)) {
|
||||||
// HotSpot does not have separate native and Java stacks, ignore silently for compatibility
|
// HotSpot does not have separate native and Java stacks, ignore silently for compatibility
|
||||||
// -Xmaxjitcodesize
|
// -Xmaxjitcodesize
|
||||||
} else if (match_option(option, "-Xmaxjitcodesize", &tail)) {
|
} else if (match_option(option, "-Xmaxjitcodesize", &tail) ||
|
||||||
|
match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) {
|
||||||
julong long_ReservedCodeCacheSize = 0;
|
julong long_ReservedCodeCacheSize = 0;
|
||||||
ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize,
|
ArgsRange errcode = parse_memory_size(tail, &long_ReservedCodeCacheSize,
|
||||||
(size_t)InitialCodeCacheSize);
|
(size_t)InitialCodeCacheSize);
|
||||||
if (errcode != arg_in_range) {
|
if (errcode != arg_in_range) {
|
||||||
jio_fprintf(defaultStream::error_stream(),
|
jio_fprintf(defaultStream::error_stream(),
|
||||||
"Invalid maximum code cache size: %s\n",
|
"Invalid maximum code cache size: %s. Should be greater than InitialCodeCacheSize=%dK\n",
|
||||||
option->optionString);
|
option->optionString, InitialCodeCacheSize/K);
|
||||||
describe_range_error(errcode);
|
describe_range_error(errcode);
|
||||||
return JNI_EINVAL;
|
return JNI_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ static jint _exiting_out_of_mem = 0;
|
||||||
|
|
||||||
void report_vm_out_of_memory(const char* file, int line, size_t size,
|
void report_vm_out_of_memory(const char* file, int line, size_t size,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
if (Debugging || error_is_suppressed(file, line)) return;
|
if (Debugging) return;
|
||||||
|
|
||||||
// We try to gather additional information for the first out of memory
|
// We try to gather additional information for the first out of memory
|
||||||
// error only; gathering additional data might cause an allocation and a
|
// error only; gathering additional data might cause an allocation and a
|
||||||
|
|
|
@ -67,7 +67,7 @@ const char *env_list[] = {
|
||||||
// threads are blocked forever inside report_and_die().
|
// threads are blocked forever inside report_and_die().
|
||||||
|
|
||||||
// Constructor for crashes
|
// Constructor for crashes
|
||||||
VMError::VMError(Thread* thread, int sig, address pc, void* siginfo, void* context) {
|
VMError::VMError(Thread* thread, unsigned int sig, address pc, void* siginfo, void* context) {
|
||||||
_thread = thread;
|
_thread = thread;
|
||||||
_id = sig;
|
_id = sig;
|
||||||
_pc = pc;
|
_pc = pc;
|
||||||
|
@ -323,28 +323,50 @@ void VMError::report(outputStream* st) {
|
||||||
STEP(10, "(printing fatal error message)")
|
STEP(10, "(printing fatal error message)")
|
||||||
|
|
||||||
st->print_cr("#");
|
st->print_cr("#");
|
||||||
|
if (should_report_bug(_id)) {
|
||||||
st->print_cr("# A fatal error has been detected by the Java Runtime Environment:");
|
st->print_cr("# A fatal error has been detected by the Java Runtime Environment:");
|
||||||
|
} else {
|
||||||
|
st->print_cr("# There is insufficient memory for the Java "
|
||||||
|
"Runtime Environment to continue.");
|
||||||
|
}
|
||||||
|
|
||||||
STEP(15, "(printing type of error)")
|
STEP(15, "(printing type of error)")
|
||||||
|
|
||||||
switch(_id) {
|
switch(_id) {
|
||||||
case oom_error:
|
case oom_error:
|
||||||
st->print_cr("#");
|
|
||||||
st->print("# java.lang.OutOfMemoryError: ");
|
|
||||||
if (_size) {
|
if (_size) {
|
||||||
st->print("requested ");
|
st->print("# Native memory allocation (malloc) failed to allocate ");
|
||||||
sprintf(buf,SIZE_FORMAT,_size);
|
jio_snprintf(buf, sizeof(buf), SIZE_FORMAT, _size);
|
||||||
st->print(buf);
|
st->print(buf);
|
||||||
st->print(" bytes");
|
st->print(" bytes");
|
||||||
if (_message != NULL) {
|
if (_message != NULL) {
|
||||||
st->print(" for ");
|
st->print(" for ");
|
||||||
st->print(_message);
|
st->print(_message);
|
||||||
}
|
}
|
||||||
st->print_cr(". Out of swap space?");
|
st->cr();
|
||||||
} else {
|
} else {
|
||||||
if (_message != NULL)
|
if (_message != NULL)
|
||||||
|
st->print("# ");
|
||||||
st->print_cr(_message);
|
st->print_cr(_message);
|
||||||
}
|
}
|
||||||
|
// In error file give some solutions
|
||||||
|
if (_verbose) {
|
||||||
|
st->print_cr("# Possible reasons:");
|
||||||
|
st->print_cr("# The system is out of physical RAM or swap space");
|
||||||
|
st->print_cr("# In 32 bit mode, the process size limit was hit");
|
||||||
|
st->print_cr("# Possible solutions:");
|
||||||
|
st->print_cr("# Reduce memory load on the system");
|
||||||
|
st->print_cr("# Increase physical memory or swap space");
|
||||||
|
st->print_cr("# Check if swap backing store is full");
|
||||||
|
st->print_cr("# Use 64 bit Java on a 64 bit OS");
|
||||||
|
st->print_cr("# Decrease Java heap size (-Xmx/-Xms)");
|
||||||
|
st->print_cr("# Decrease number of Java threads");
|
||||||
|
st->print_cr("# Decrease Java thread stack sizes (-Xss)");
|
||||||
|
st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize=");
|
||||||
|
st->print_cr("# This output file may be truncated or incomplete.");
|
||||||
|
} else {
|
||||||
|
return; // that's enough for the screen
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case internal_error:
|
case internal_error:
|
||||||
default:
|
default:
|
||||||
|
@ -361,7 +383,11 @@ void VMError::report(outputStream* st) {
|
||||||
st->print(" (0x%x)", _id); // signal number
|
st->print(" (0x%x)", _id); // signal number
|
||||||
st->print(" at pc=" PTR_FORMAT, _pc);
|
st->print(" at pc=" PTR_FORMAT, _pc);
|
||||||
} else {
|
} else {
|
||||||
|
if (should_report_bug(_id)) {
|
||||||
st->print("Internal Error");
|
st->print("Internal Error");
|
||||||
|
} else {
|
||||||
|
st->print("Out of Memory Error");
|
||||||
|
}
|
||||||
if (_filename != NULL && _lineno > 0) {
|
if (_filename != NULL && _lineno > 0) {
|
||||||
#ifdef PRODUCT
|
#ifdef PRODUCT
|
||||||
// In product mode chop off pathname?
|
// In product mode chop off pathname?
|
||||||
|
@ -393,12 +419,14 @@ void VMError::report(outputStream* st) {
|
||||||
|
|
||||||
STEP(40, "(printing error message)")
|
STEP(40, "(printing error message)")
|
||||||
|
|
||||||
|
if (should_report_bug(_id)) { // already printed the message.
|
||||||
// error message
|
// error message
|
||||||
if (_detail_msg) {
|
if (_detail_msg) {
|
||||||
st->print_cr("# %s: %s", _message ? _message : "Error", _detail_msg);
|
st->print_cr("# %s: %s", _message ? _message : "Error", _detail_msg);
|
||||||
} else if (_message) {
|
} else if (_message) {
|
||||||
st->print_cr("# Error: %s", _message);
|
st->print_cr("# Error: %s", _message);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
STEP(50, "(printing Java version string)")
|
STEP(50, "(printing Java version string)")
|
||||||
|
|
||||||
|
@ -428,7 +456,9 @@ void VMError::report(outputStream* st) {
|
||||||
|
|
||||||
STEP(65, "(printing bug submit message)")
|
STEP(65, "(printing bug submit message)")
|
||||||
|
|
||||||
if (_verbose) print_bug_submit_message(st, _thread);
|
if (should_report_bug(_id) && _verbose) {
|
||||||
|
print_bug_submit_message(st, _thread);
|
||||||
|
}
|
||||||
|
|
||||||
STEP(70, "(printing thread)" )
|
STEP(70, "(printing thread)" )
|
||||||
|
|
||||||
|
@ -906,7 +936,7 @@ void VMError::report_and_die() {
|
||||||
OnError = NULL;
|
OnError = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool skip_bug_url = false;
|
static bool skip_bug_url = !should_report_bug(first_error->_id);
|
||||||
if (!skip_bug_url) {
|
if (!skip_bug_url) {
|
||||||
skip_bug_url = true;
|
skip_bug_url = true;
|
||||||
|
|
||||||
|
@ -919,7 +949,8 @@ void VMError::report_and_die() {
|
||||||
static bool skip_os_abort = false;
|
static bool skip_os_abort = false;
|
||||||
if (!skip_os_abort) {
|
if (!skip_os_abort) {
|
||||||
skip_os_abort = true;
|
skip_os_abort = true;
|
||||||
os::abort();
|
bool dump_core = should_report_bug(first_error->_id);
|
||||||
|
os::abort(dump_core);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if os::abort() doesn't abort, try os::die();
|
// if os::abort() doesn't abort, try os::die();
|
||||||
|
|
|
@ -87,10 +87,12 @@ class VMError : public StackObj {
|
||||||
// accessor
|
// accessor
|
||||||
const char* message() const { return _message; }
|
const char* message() const { return _message; }
|
||||||
const char* detail_msg() const { return _detail_msg; }
|
const char* detail_msg() const { return _detail_msg; }
|
||||||
|
bool should_report_bug(unsigned int id) { return id != oom_error; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor for crashes
|
// Constructor for crashes
|
||||||
VMError(Thread* thread, int sig, address pc, void* siginfo, void* context);
|
VMError(Thread* thread, unsigned int sig, address pc, void* siginfo,
|
||||||
|
void* context);
|
||||||
// Constructor for VM internal errors
|
// Constructor for VM internal errors
|
||||||
VMError(Thread* thread, const char* filename, int lineno,
|
VMError(Thread* thread, const char* filename, int lineno,
|
||||||
const char* message, const char * detail_msg);
|
const char* message, const char * detail_msg);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue