< prev index next >
src/hotspot/share/memory/metaspace.cpp
Print this page
@@ -21,13 +21,14 @@
* questions.
*
*/
#include "precompiled.hpp"
#include "aot/aotLoader.hpp"
+#include "classfile/classLoaderData.hpp"
#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/collectorPolicy.hpp"
-#include "gc/shared/gcLocker.hpp"
+#include "gc/shared/gcLocker.inline.hpp"
+#include "gc/shared/vmGCOperations.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.hpp"
#include "memory/binaryTreeDictionary.hpp"
#include "memory/filemap.hpp"
@@ -43,10 +44,11 @@
#include "runtime/globals.hpp"
#include "runtime/init.hpp"
#include "runtime/java.hpp"
#include "runtime/mutex.hpp"
#include "runtime/orderAccess.inline.hpp"
+#include "runtime/vmThread.hpp"
#include "services/memTracker.hpp"
#include "services/memoryService.hpp"
#include "utilities/align.hpp"
#include "utilities/copy.hpp"
#include "utilities/debug.hpp"
@@ -1819,10 +1821,84 @@
new_capacity_until_GC,
MetaspaceGCThresholdUpdater::ComputeNewSize);
}
}
+MetaWord* MetaspaceGC::satisfy_failed_metadata_allocation(ClassLoaderData* loader_data,
+ size_t word_size,
+ Metaspace::MetadataType mdtype) {
+ uint loop_count = 0;
+ uint gc_count = 0;
+ uint full_gc_count = 0;
+
+ assert(!Heap_lock->owned_by_self(), "Should not be holding the Heap_lock");
+
+ do {
+ MetaWord* result = loader_data->metaspace_non_null()->allocate(word_size, mdtype);
+ if (result != NULL) {
+ return result;
+ }
+
+ if (GCLocker::is_active_and_needs_gc()) {
+ // If the GCLocker is active, just expand and allocate.
+ // If that does not succeed, wait if this thread is not
+ // in a critical section itself.
+ result = loader_data->metaspace_non_null()->expand_and_allocate(word_size, mdtype);
+ if (result != NULL) {
+ return result;
+ }
+ JavaThread* jthr = JavaThread::current();
+ if (!jthr->in_critical()) {
+ // Wait for JNI critical section to be exited
+ GCLocker::stall_until_clear();
+ // The GC invoked by the last thread leaving the critical
+ // section will be a young collection and a full collection
+ // is (currently) needed for unloading classes so continue
+ // to the next iteration to get a full GC.
+ continue;
+ } else {
+ if (CheckJNICalls) {
+ fatal("Possible deadlock due to allocating while"
+ " in jni critical section");
+ }
+ return NULL;
+ }
+ }
+
+ { // Need lock to get self consistent gc_count's
+ MutexLocker ml(Heap_lock);
+ gc_count = Universe::heap()->total_collections();
+ full_gc_count = Universe::heap()->total_full_collections();
+ }
+
+ // Generate a VM operation
+ VM_CollectForMetadataAllocation op(loader_data,
+ word_size,
+ mdtype,
+ gc_count,
+ full_gc_count,
+ GCCause::_metadata_GC_threshold);
+ VMThread::execute(&op);
+
+ // If GC was locked out, try again. Check before checking success because the
+ // prologue could have succeeded and the GC still have been locked out.
+ if (op.gc_locked()) {
+ continue;
+ }
+
+ if (op.prologue_succeeded()) {
+ return op.result();
+ }
+ loop_count++;
+ if ((QueuedAllocationWarningCount > 0) &&
+ (loop_count % QueuedAllocationWarningCount == 0)) {
+ log_warning(gc, ergo)("satisfy_failed_metadata_allocation() retries %d times,"
+ " size=" SIZE_FORMAT, loop_count, word_size);
+ }
+ } while (true); // Until a GC is done
+}
+
// Metadebug methods
void Metadebug::init_allocation_fail_alot_count() {
if (MetadataAllocationFailALot) {
_allocation_fail_alot_count =
@@ -3950,12 +4026,11 @@
// Allocation failed.
if (is_init_completed()) {
// Only start a GC if the bootstrapping has completed.
// Try to clean out some memory and retry.
- result = Universe::heap()->collector_policy()->satisfy_failed_metadata_allocation(
- loader_data, word_size, mdtype);
+ result = Universe::heap()->satisfy_failed_metadata_allocation(loader_data, word_size, mdtype);
}
}
if (result == NULL) {
SpaceManager* sm;
< prev index next >