8037842: Failing to allocate MethodCounters and MDO causes a serious performance drop

Stop allocating compiler profiling metadata when metaspace is full.

Reviewed-by: kvn, anoll
This commit is contained in:
Coleen Phillimore 2014-10-30 18:38:42 -04:00
parent b301b207b3
commit 4c036f5730
5 changed files with 62 additions and 4 deletions

View file

@ -553,6 +553,7 @@ ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL;
ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL; ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
bool ClassLoaderDataGraph::_should_purge = false; bool ClassLoaderDataGraph::_should_purge = false;
bool ClassLoaderDataGraph::_metaspace_oom = false;
// Add a new class loader data node to the list. Assign the newly created // Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field // ClassLoaderData into the java/lang/ClassLoader object as a hidden field
@ -804,12 +805,17 @@ void ClassLoaderDataGraph::purge() {
ClassLoaderData* list = _unloading; ClassLoaderData* list = _unloading;
_unloading = NULL; _unloading = NULL;
ClassLoaderData* next = list; ClassLoaderData* next = list;
bool classes_unloaded = false;
while (next != NULL) { while (next != NULL) {
ClassLoaderData* purge_me = next; ClassLoaderData* purge_me = next;
next = purge_me->next(); next = purge_me->next();
delete purge_me; delete purge_me;
classes_unloaded = true;
}
if (classes_unloaded) {
Metaspace::purge();
set_metaspace_oom(false);
} }
Metaspace::purge();
} }
void ClassLoaderDataGraph::post_class_unload_events(void) { void ClassLoaderDataGraph::post_class_unload_events(void) {

View file

@ -68,6 +68,9 @@ class ClassLoaderDataGraph : public AllStatic {
static ClassLoaderData* _saved_head; static ClassLoaderData* _saved_head;
static ClassLoaderData* _saved_unloading; static ClassLoaderData* _saved_unloading;
static bool _should_purge; static bool _should_purge;
// OOM has been seen in metaspace allocation. Used to prevent some
// allocations until class unloading
static bool _metaspace_oom;
static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS); static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
static void post_class_unload_events(void); static void post_class_unload_events(void);
@ -107,6 +110,9 @@ class ClassLoaderDataGraph : public AllStatic {
} }
} }
static bool has_metaspace_oom() { return _metaspace_oom; }
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
static void free_deallocate_lists(); static void free_deallocate_lists();
static void dump_on(outputStream * const out) PRODUCT_RETURN; static void dump_on(outputStream * const out) PRODUCT_RETURN;

View file

@ -187,6 +187,14 @@ class CompilationLog : public StringEventLog {
lm.print("\n"); lm.print("\n");
log(thread, "%s", (const char*)lm); log(thread, "%s", (const char*)lm);
} }
void log_metaspace_failure(const char* reason) {
ResourceMark rm;
StringLogMessage lm;
lm.print("%4d COMPILE PROFILING SKIPPED: %s", -1, reason);
lm.print("\n");
log(JavaThread::current(), "%s", (const char*)lm);
}
}; };
static CompilationLog* _compilation_log = NULL; static CompilationLog* _compilation_log = NULL;
@ -1843,6 +1851,18 @@ void CompileBroker::init_compiler_thread_log() {
warning("Cannot open log file: %s", file_name); warning("Cannot open log file: %s", file_name);
} }
void CompileBroker::log_metaspace_failure() {
const char* message = "some methods may not be compiled because metaspace "
"is out of memory";
if (_compilation_log != NULL) {
_compilation_log->log_metaspace_failure(message);
}
if (PrintCompilation) {
tty->print_cr("COMPILE PROFILING SKIPPED: %s", message);
}
}
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// CompileBroker::set_should_block // CompileBroker::set_should_block
// //

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -473,6 +473,9 @@ class CompileBroker: AllStatic {
static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; } static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; }
static long get_peak_compilation_time() { return _peak_compilation_time; } static long get_peak_compilation_time() { return _peak_compilation_time; }
static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); } static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); }
// Log that compilation profiling is skipped because metaspace is full.
static void log_metaspace_failure();
}; };
#endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP #endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP

View file

@ -368,6 +368,13 @@ void Method::print_invocation_count() {
// Build a MethodData* object to hold information about this method // Build a MethodData* object to hold information about this method
// collected in the interpreter. // collected in the interpreter.
void Method::build_interpreter_method_data(methodHandle method, TRAPS) { void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
// Do not profile the method if metaspace has hit an OOM previously
// allocating profiling data. Callers clear pending exception so don't
// add one here.
if (ClassLoaderDataGraph::has_metaspace_oom()) {
return;
}
// Do not profile method if current thread holds the pending list lock, // Do not profile method if current thread holds the pending list lock,
// which avoids deadlock for acquiring the MethodData_lock. // which avoids deadlock for acquiring the MethodData_lock.
if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) { if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
@ -379,7 +386,13 @@ void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
MutexLocker ml(MethodData_lock, THREAD); MutexLocker ml(MethodData_lock, THREAD);
if (method->method_data() == NULL) { if (method->method_data() == NULL) {
ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
MethodData* method_data = MethodData::allocate(loader_data, method, CHECK); MethodData* method_data = MethodData::allocate(loader_data, method, THREAD);
if (HAS_PENDING_EXCEPTION) {
CompileBroker::log_metaspace_failure();
ClassLoaderDataGraph::set_metaspace_oom(true);
return; // return the exception (which is cleared)
}
method->set_method_data(method_data); method->set_method_data(method_data);
if (PrintMethodData && (Verbose || WizardMode)) { if (PrintMethodData && (Verbose || WizardMode)) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
@ -392,9 +405,19 @@ void Method::build_interpreter_method_data(methodHandle method, TRAPS) {
} }
MethodCounters* Method::build_method_counters(Method* m, TRAPS) { MethodCounters* Method::build_method_counters(Method* m, TRAPS) {
// Do not profile the method if metaspace has hit an OOM previously
if (ClassLoaderDataGraph::has_metaspace_oom()) {
return NULL;
}
methodHandle mh(m); methodHandle mh(m);
ClassLoaderData* loader_data = mh->method_holder()->class_loader_data(); ClassLoaderData* loader_data = mh->method_holder()->class_loader_data();
MethodCounters* counters = MethodCounters::allocate(loader_data, CHECK_NULL); MethodCounters* counters = MethodCounters::allocate(loader_data, THREAD);
if (HAS_PENDING_EXCEPTION) {
CompileBroker::log_metaspace_failure();
ClassLoaderDataGraph::set_metaspace_oom(true);
return NULL; // return the exception (which is cleared)
}
if (!mh->init_method_counters(counters)) { if (!mh->init_method_counters(counters)) {
MetadataFactory::free_metadata(loader_data, counters); MetadataFactory::free_metadata(loader_data, counters);
} }