# HG changeset patch # User ehelin # Date 1401366688 -7200 # Node ID 37c354b113fe48a6271ea9ded6bd53378e931ff8 # Parent 269aeb9131ba454e8d7bf9cbbff23ab3763b02f4 8042933: assert(capacity_until_gc >= committed_bytes) failed Reviewed-by: stefank, jmasa diff -r 269aeb9131ba -r 37c354b113fe hotspot/src/share/vm/memory/metaspace.cpp --- a/hotspot/src/share/vm/memory/metaspace.cpp Tue Jun 03 09:34:04 2014 +0000 +++ b/hotspot/src/share/vm/memory/metaspace.cpp Thu May 29 14:31:28 2014 +0200 @@ -1423,6 +1423,17 @@ return (size_t)Atomic::add_ptr(-(intptr_t)v, &_capacity_until_GC); } +void MetaspaceGC::initialize() { + // Set the high-water mark to MaxMetapaceSize during VM initializaton since + // we can't do a GC during initialization. + _capacity_until_GC = MaxMetaspaceSize; +} + +void MetaspaceGC::post_initialize() { + // Reset the high-water mark once the VM initialization is done. + _capacity_until_GC = MAX2(MetaspaceAux::committed_bytes(), MetaspaceSize); +} + bool MetaspaceGC::can_expand(size_t word_size, bool is_class) { // Check if the compressed class space is full. if (is_class && Metaspace::using_class_space()) { @@ -1443,21 +1454,13 @@ size_t MetaspaceGC::allowed_expansion() { size_t committed_bytes = MetaspaceAux::committed_bytes(); + size_t capacity_until_gc = capacity_until_GC(); + + assert(capacity_until_gc >= committed_bytes, + err_msg("capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, + capacity_until_gc, committed_bytes)); size_t left_until_max = MaxMetaspaceSize - committed_bytes; - - // Always grant expansion if we are initiating the JVM, - // or if the GC_locker is preventing GCs. - if (!is_init_completed() || GC_locker::is_active_and_needs_gc()) { - return left_until_max / BytesPerWord; - } - - size_t capacity_until_gc = capacity_until_GC(); - - if (capacity_until_gc <= committed_bytes) { - return 0; - } - size_t left_until_GC = capacity_until_gc - committed_bytes; size_t left_to_commit = MIN2(left_until_GC, left_until_max); @@ -1469,7 +1472,15 @@ uint current_shrink_factor = _shrink_factor; _shrink_factor = 0; - const size_t used_after_gc = MetaspaceAux::capacity_bytes(); + // Using committed_bytes() for used_after_gc is an overestimation, since the + // chunk free lists are included in committed_bytes() and the memory in an + // un-fragmented chunk free list is available for future allocations. + // However, if the chunk free lists becomes fragmented, then the memory may + // not be available for future allocations and the memory is therefore "in use". + // Including the chunk free lists in the definition of "in use" is therefore + // necessary. Not including the chunk free lists can cause capacity_until_GC to + // shrink below committed_bytes() and this has caused serious bugs in the past. + const size_t used_after_gc = MetaspaceAux::committed_bytes(); const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC(); const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0; @@ -3094,6 +3105,8 @@ } void Metaspace::global_initialize() { + MetaspaceGC::initialize(); + // Initialize the alignment for shared spaces. int max_alignment = os::vm_allocation_granularity(); size_t cds_total = 0; @@ -3201,10 +3214,13 @@ } } - MetaspaceGC::initialize(); _tracer = new MetaspaceTracer(); } +void Metaspace::post_initialize() { + MetaspaceGC::post_initialize(); +} + Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, size_t chunk_word_size, size_t chunk_bunch) { diff -r 269aeb9131ba -r 37c354b113fe hotspot/src/share/vm/memory/metaspace.hpp --- a/hotspot/src/share/vm/memory/metaspace.hpp Tue Jun 03 09:34:04 2014 +0000 +++ b/hotspot/src/share/vm/memory/metaspace.hpp Thu May 29 14:31:28 2014 +0200 @@ -208,6 +208,7 @@ static void ergo_initialize(); static void global_initialize(); + static void post_initialize(); static size_t first_chunk_word_size() { return _first_chunk_word_size; } static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; } @@ -398,7 +399,8 @@ public: - static void initialize() { _capacity_until_GC = MetaspaceSize; } + static void initialize(); + static void post_initialize(); static size_t capacity_until_GC(); static size_t inc_capacity_until_GC(size_t v); diff -r 269aeb9131ba -r 37c354b113fe hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Tue Jun 03 09:34:04 2014 +0000 +++ b/hotspot/src/share/vm/runtime/thread.cpp Thu May 29 14:31:28 2014 +0200 @@ -3543,6 +3543,8 @@ // debug stuff, that does not work until all basic classes have been initialized. set_init_completed(); + Metaspace::post_initialize(); + HOTSPOT_VM_INIT_END(); // record VM initialization completion time diff -r 269aeb9131ba -r 37c354b113fe hotspot/test/gc/metaspace/TestMetaspaceInitialization.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/metaspace/TestMetaspaceInitialization.java Thu May 29 14:31:28 2014 +0200 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.ArrayList; + +/* @test TestMetaspaceInitialization + * @bug 8042933 + * @summary Tests to initialize metaspace with a very low MetaspaceSize + * @library /testlibrary + * @run main/othervm -XX:MetaspaceSize=2m TestMetaspaceInitialization + */ +public class TestMetaspaceInitialization { + private class Internal { + public int x; + public Internal(int x) { + this.x = x; + } + } + + private void test() { + ArrayList l = new ArrayList<>(); + l.add(new Internal(17)); + } + + public static void main(String[] args) { + new TestMetaspaceInitialization().test(); + } +}