--- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2014-12-15 10:41:31.112363036 +0100 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2014-12-15 10:41:31.041361010 +0100 @@ -3488,8 +3488,24 @@ private: size_t _total_humongous; size_t _candidate_humongous; + + DirtyCardQueue _dcq; + + bool humongous_region_is_candidate(uint index) { + HeapRegion* region = G1CollectedHeap::heap()->region_at(index); + assert(region->is_starts_humongous(), "Must start a humongous object"); + HeapRegionRemSet* const rset = region->rem_set(); + bool const allow_stale_refs = G1ReclaimDeadHumongousObjectsWithStaleRefsAtYoungGC; + return !oop(region->bottom())->is_objArray() && + ((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) || + (!allow_stale_refs && rset->is_empty())); + } + public: - RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) { + RegisterHumongousWithInCSetFastTestClosure() + : _total_humongous(0), + _candidate_humongous(0), + _dcq(&JavaThread::dirty_card_queue_set()) { } virtual bool doHeapRegion(HeapRegion* r) { @@ -3499,11 +3515,29 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); uint region_idx = r->hrm_index(); - bool is_candidate = !g1h->humongous_region_is_always_live(region_idx); - // Is_candidate already filters out humongous regions with some remembered set. - // This will not lead to humongous object that we mistakenly keep alive because - // during young collection the remembered sets will only be added to. + bool is_candidate = humongous_region_is_candidate(region_idx); + // Is_candidate already filters out humongous object with large remembered sets. + // If we have a humongous object with a few remembered sets, we simply flush these + // remembered set entries into the DCQS. That will result in automatic + // re-evaluation of their remembered set entries during the following evacuation + // phase. if (is_candidate) { + if (!r->rem_set()->is_empty()) { + guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries), + "Found a not-small remembered set here. This is inconsistent with previous assumptions."); + G1SATBCardTableLoggingModRefBS* bs = g1h->g1_barrier_set(); + HeapRegionRemSetIterator hrrs(r->rem_set()); + size_t card_index; + while (hrrs.has_next(card_index)) { + jbyte* card_ptr = (jbyte*)bs->byte_for_index(card_index); + if (*card_ptr != CardTableModRefBS::dirty_card_val()) { + *card_ptr = CardTableModRefBS::dirty_card_val(); + _dcq.enqueue(card_ptr); + } + } + r->rem_set()->clear_locked(); + } + assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty."); g1h->register_humongous_region_with_in_cset_fast_test(region_idx); _candidate_humongous++; } @@ -3514,23 +3548,32 @@ size_t total_humongous() const { return _total_humongous; } size_t candidate_humongous() const { return _candidate_humongous; } + + void flush_rem_set_entries() { _dcq.flush(); } }; void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() { if (!G1ReclaimDeadHumongousObjectsAtYoungGC) { - g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0); + g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0); return; } + double time = os::elapsed_counter(); RegisterHumongousWithInCSetFastTestClosure cl; heap_region_iterate(&cl); - g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(), + + time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0; + g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(time, + cl.total_humongous(), cl.candidate_humongous()); _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0; if (_has_humongous_reclaim_candidates || G1TraceReclaimDeadHumongousObjectsAtYoungGC) { clear_humongous_is_live_table(); } + + // Finally flush all remembered set entries to re-check into the global DCQS. + cl.flush_rem_set_entries(); } void @@ -6133,22 +6176,20 @@ // are completely up-to-date wrt to references to the humongous object. // // Other implementation considerations: - // - never consider object arrays: while they are a valid target, they have not - // been observed to be used as temporary objects. - // - they would also pose considerable effort for cleaning up the the remembered - // sets. - // While this cleanup is not strictly necessary to be done (or done instantly), - // given that their occurrence is very low, this saves us this additional - // complexity. + // - never consider object arrays at this time because they would pose + // considerable effort for cleaning up the the remembered sets. This is + // required because stale remembered sets might reference locations that + // are currently allocated into. uint region_idx = r->hrm_index(); if (g1h->humongous_is_live(region_idx) || g1h->humongous_region_is_always_live(region_idx)) { if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { - gclog_or_tty->print_cr("Live humongous %d region %d size "SIZE_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", - r->is_humongous(), + gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", region_idx, obj->size()*HeapWordSize, + r->bottom(), + r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), next_bitmap->isMarked(r->bottom()), @@ -6165,11 +6206,10 @@ r->bottom())); if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) { - gclog_or_tty->print_cr("Reclaim humongous region %d size "SIZE_FORMAT" start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", - r->is_humongous(), + gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d", + region_idx, obj->size()*HeapWordSize, r->bottom(), - region_idx, r->region_num(), r->rem_set()->occupied(), r->rem_set()->strong_code_roots_list_length(), --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2014-12-15 10:41:31.562375877 +0100 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2014-12-15 10:41:31.496373993 +0100 @@ -676,6 +676,9 @@ // Returns whether the given region (which must be a humongous (start) region) // is to be considered conservatively live regardless of any other conditions. bool humongous_region_is_always_live(uint index); + // Returns whether the given region (which must be a humongous (start) region) + // is considered a candidate for eager reclamation. + bool humongous_region_is_candidate(uint index); // Register the given region to be part of the collection set. inline void register_humongous_region_with_in_cset_fast_test(uint index); // Register regions with humongous objects (actually on the start region) in --- old/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp 2014-12-15 10:41:31.949386920 +0100 +++ new/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp 2014-12-15 10:41:31.883385037 +0100 @@ -345,10 +345,13 @@ _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards"); } if (G1ReclaimDeadHumongousObjectsAtYoungGC) { - print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); if (G1Log::finest()) { print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total); print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates); + } + print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + if (G1Log::finest()) { print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); } } --- old/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp 2014-12-15 10:41:32.362398705 +0100 +++ new/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp 2014-12-15 10:41:32.293396736 +0100 @@ -157,6 +157,7 @@ double _recorded_non_young_free_cset_time_ms; double _cur_fast_reclaim_humongous_time_ms; + double _cur_fast_reclaim_humongous_register_time_ms; size_t _cur_fast_reclaim_humongous_total; size_t _cur_fast_reclaim_humongous_candidates; size_t _cur_fast_reclaim_humongous_reclaimed; @@ -283,7 +284,8 @@ _recorded_non_young_free_cset_time_ms = time_ms; } - void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) { + void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) { + _cur_fast_reclaim_humongous_register_time_ms = time_ms; _cur_fast_reclaim_humongous_total = total; _cur_fast_reclaim_humongous_candidates = candidates; } --- old/src/share/vm/gc_implementation/g1/g1_globals.hpp 2014-12-15 10:41:32.742409549 +0100 +++ new/src/share/vm/gc_implementation/g1/g1_globals.hpp 2014-12-15 10:41:32.674407608 +0100 @@ -273,6 +273,10 @@ experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \ "Try to reclaim dead large objects at every young GC.") \ \ + experimental(bool, G1ReclaimDeadHumongousObjectsWithStaleRefsAtYoungGC, true, \ + "Try to reclaim dead large objects that have a few stale " \ + "references at every young GC.") \ + \ experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, false, \ "Print some information about large object liveness " \ "at every young GC.") \ --- old/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp 2014-12-15 10:41:33.115420192 +0100 +++ new/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp 2014-12-15 10:41:33.050418338 +0100 @@ -681,6 +681,19 @@ clear_fcc(); } +bool OtherRegionsTable::occupancy_less_or_equal_than(size_t occ) const { + guarantee(occ <= (size_t)G1RSetSparseRegionEntries, + err_msg("Requested maximum occupancy must be smaller or equal than " + SIZE_FORMAT" but is " SIZE_FORMAT, (size_t)G1RSetSparseRegionEntries, occ)); + // The following statement is a simplification: although the predicate gives a + // value for the maximum total allowed remembered set entries we always only + // ever check the sparse remembered set for it. + // Getting the actual occupancy of even a single fine remembered set (a single + // coarse entry will almost always exceed the number the sparse remembered set can + // hold so we just check for zero here) is very expensive, so we do not do it. + return occ_coarse() == 0 && _first_all_fine_prts == NULL && occ_sparse() <= occ; +} + bool OtherRegionsTable::is_empty() const { return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL; } --- old/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp 2014-12-15 10:41:33.493430979 +0100 +++ new/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp 2014-12-15 10:41:33.428429124 +0100 @@ -183,6 +183,10 @@ // Returns whether the remembered set contains the given reference. bool contains_reference(OopOrNarrowOopStar from) const; + // Returns whether this remembered set (and all sub-sets) have an occupancy + // that is less or equal than the given occupancy. + bool occupancy_less_or_equal_than(size_t occ) const; + // Removes any entries shown by the given bitmaps to contain only dead // objects. Not thread safe. // Set bits in the bitmaps indicate that the given region or card is live. @@ -261,6 +265,10 @@ return (strong_code_roots_list_length() == 0) && _other_regions.is_empty(); } + bool occupancy_less_or_equal_than(size_t occ) const { + return (strong_code_roots_list_length() == 0) && _other_regions.occupancy_less_or_equal_than(occ); + } + size_t occupied() { MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); return occupied_locked(); --- old/test/gc/g1/TestG1TraceReclaimDeadHumongousObjectsAtYoungGC.java 2014-12-15 10:41:33.870441737 +0100 +++ new/test/gc/g1/TestG1TraceReclaimDeadHumongousObjectsAtYoungGC.java 2014-12-15 10:41:33.804439853 +0100 @@ -88,7 +88,7 @@ // As G1TraceReclaimDeadHumongousObjectsAtYoungGC is set and GCWithHumongousObjectTest has humongous objects, // these logs should be displayed. output.shouldContain("Live humongous"); - output.shouldContain("Reclaim humongous region"); + output.shouldContain("Dead humongous region"); output.shouldHaveExitValue(0); } --- old/test/gc/g1/TestGCLogMessages.java 2014-12-15 10:41:34.240452295 +0100 +++ new/test/gc/g1/TestGCLogMessages.java 2014-12-15 10:41:34.175450440 +0100 @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 * @summary Ensure that the PrintGCDetails output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -54,6 +54,7 @@ output.shouldNotContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); + output.shouldNotContain("[Humongous Register"); output.shouldNotContain("[Humongous Reclaim"); output.shouldHaveExitValue(0); @@ -72,9 +73,10 @@ output.shouldContain("[String Dedup Fixup"); output.shouldNotContain("[Young Free CSet"); output.shouldNotContain("[Non-Young Free CSet"); - output.shouldContain("[Humongous Reclaim"); + output.shouldContain("[Humongous Register"); output.shouldNotContain("[Humongous Total"); output.shouldNotContain("[Humongous Candidate"); + output.shouldContain("[Humongous Reclaim"); output.shouldNotContain("[Humongous Reclaimed"); output.shouldHaveExitValue(0); @@ -95,9 +97,10 @@ output.shouldContain("[String Dedup Fixup"); output.shouldContain("[Young Free CSet"); output.shouldContain("[Non-Young Free CSet"); - output.shouldContain("[Humongous Reclaim"); + output.shouldContain("[Humongous Register"); output.shouldContain("[Humongous Total"); output.shouldContain("[Humongous Candidate"); + output.shouldContain("[Humongous Reclaim"); output.shouldContain("[Humongous Reclaimed"); output.shouldHaveExitValue(0); } --- old/test/gc/g1/TestEagerReclaimHumongousRegions2.java 2014-12-15 10:41:34.655464137 +0100 +++ /dev/null 2014-12-12 17:10:47.511674808 +0100 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2014, 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. - */ - -/* - * @test TestEagerReclaimHumongousRegions2 - * @bug 8051973 - * @summary Test to make sure that eager reclaim of humongous objects correctly clears - * mark bitmaps at reclaim. - * @key gc - * @library /testlibrary - */ - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.Random; - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - -// An object that has a few references to other instances to slow down marking. -class ObjectWithSomeRefs { - public ObjectWithSomeRefs other1; - public ObjectWithSomeRefs other2; - public ObjectWithSomeRefs other3; - public ObjectWithSomeRefs other4; -} - -class ReclaimRegionFast { - public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test. - - public static final int M = 1024*1024; - - public static LinkedList garbageList = new LinkedList(); - - public static void genGarbage(Object large) { - for (int i = 0; i < 64*1024; i++) { - Object[] garbage = new Object[50]; - garbage[0] = large; - garbageList.add(garbage); - } - garbageList.clear(); - } - - public static ArrayList longList = new ArrayList(); - - public static void main(String[] args) { - - for (int i = 0; i < 16*1024; i++) { - longList.add(new ObjectWithSomeRefs()); - } - - Random rnd = new Random(); - for (int i = 0; i < longList.size(); i++) { - int len = longList.size(); - longList.get(i).other1 = longList.get(rnd.nextInt(len)); - longList.get(i).other2 = longList.get(rnd.nextInt(len)); - longList.get(i).other3 = longList.get(rnd.nextInt(len)); - longList.get(i).other4 = longList.get(rnd.nextInt(len)); - } - - int[] large1 = new int[M]; - int[] large2 = null; - int[] large3 = null; - int[] large4 = null; - - Object ref_from_stack = large1; - - long start_millis = System.currentTimeMillis(); - - for (int i = 0; i < 20; i++) { - long current_millis = System.currentTimeMillis(); - if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) { - System.out.println("Finishing test because maximum runtime exceeded"); - break; - } - // A set of large objects that will be reclaimed eagerly - and hopefully marked. - large1 = new int[M - 20]; - large2 = new int[M - 20]; - large3 = new int[M - 20]; - large4 = new int[M - 20]; - genGarbage(large1); - // Make sure that the compiler cannot completely remove - // the allocation of the large object until here. - System.out.println(large1 + " " + large2 + " " + large3 + " " + large4); - } - - // Keep the reference to the first object alive. - System.out.println(ref_from_stack); - } -} - -public class TestEagerReclaimHumongousRegions2 { - public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - "-XX:+UseG1GC", - "-Xms128M", - "-Xmx128M", - "-Xmn2M", - "-XX:G1HeapRegionSize=1M", - "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks. - "-XX:+PrintGC", - "-XX:+VerifyAfterGC", - "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. - "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only. - "-XX:+G1VerifyBitmaps", - ReclaimRegionFast.class.getName()); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldHaveExitValue(0); - } -} - --- /dev/null 2014-12-12 17:10:47.511674808 +0100 +++ new/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java 2014-12-15 10:41:34.543460941 +0100 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * @test TestEagerReclaimHumongousRegionsClearMarkBits + * @bug 8051973 + * @summary Test to make sure that eager reclaim of humongous objects correctly clears + * mark bitmaps at reclaim. + * @key gc + * @library /testlibrary + */ + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Random; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; + +// An object that has a few references to other instances to slow down marking. +class ObjectWithSomeRefs { + public ObjectWithSomeRefs other1; + public ObjectWithSomeRefs other2; + public ObjectWithSomeRefs other3; + public ObjectWithSomeRefs other4; +} + +class ReclaimRegionFast { + public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test. + + public static final int M = 1024*1024; + + public static LinkedList garbageList = new LinkedList(); + + public static void genGarbage(Object large) { + for (int i = 0; i < 64*1024; i++) { + Object[] garbage = new Object[50]; + garbage[0] = large; + garbageList.add(garbage); + } + garbageList.clear(); + } + + public static ArrayList longList = new ArrayList(); + + public static void main(String[] args) { + + for (int i = 0; i < 16*1024; i++) { + longList.add(new ObjectWithSomeRefs()); + } + + Random rnd = new Random(); + for (int i = 0; i < longList.size(); i++) { + int len = longList.size(); + longList.get(i).other1 = longList.get(rnd.nextInt(len)); + longList.get(i).other2 = longList.get(rnd.nextInt(len)); + longList.get(i).other3 = longList.get(rnd.nextInt(len)); + longList.get(i).other4 = longList.get(rnd.nextInt(len)); + } + + int[] large1 = new int[M]; + int[] large2 = null; + int[] large3 = null; + int[] large4 = null; + + Object ref_from_stack = large1; + + long start_millis = System.currentTimeMillis(); + + for (int i = 0; i < 20; i++) { + long current_millis = System.currentTimeMillis(); + if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) { + System.out.println("Finishing test because maximum runtime exceeded"); + break; + } + // A set of large objects that will be reclaimed eagerly - and hopefully marked. + large1 = new int[M - 20]; + large2 = new int[M - 20]; + large3 = new int[M - 20]; + large4 = new int[M - 20]; + genGarbage(large1); + // Make sure that the compiler cannot completely remove + // the allocation of the large object until here. + System.out.println(large1 + " " + large2 + " " + large3 + " " + large4); + } + + // Keep the reference to the first object alive. + System.out.println(ref_from_stack); + } +} + +public class TestEagerReclaimHumongousRegionsClearMarkBits { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn2M", + "-XX:G1HeapRegionSize=1M", + "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks. + "-XX:+PrintGC", + "-XX:+VerifyAfterGC", + "-XX:ConcGCThreads=1", // Want to make marking as slow as possible. + "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only. + "-XX:+G1VerifyBitmaps", + ReclaimRegionFast.class.getName()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } +} + --- /dev/null 2014-12-12 17:10:47.511674808 +0100 +++ new/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java 2014-12-15 10:41:34.961472869 +0100 @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014, 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. + */ + +/* + * @test TestEagerReclaimHumongousRegionsWithRefs + * @bug 8048179 + * @summary Test to make sure that eager reclaim of humongous objects that have previously + * been referenced by other old gen regions work. We simply try to fill + * up the heap with humongous objects and create a remembered set entry from an object by + * referencing that we know is in the old gen. After changing this reference, the object + * should still be eagerly reclaimable to avoid Full GC. + * @key gc + * @library /testlibrary + */ + +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.LinkedList; + +import com.oracle.java.testlibrary.OutputAnalyzer; +import com.oracle.java.testlibrary.ProcessTools; +import static com.oracle.java.testlibrary.Asserts.*; + +class RefHolder { + Object ref; +} + +class ReclaimRegionFast { + + public static final int M = 1024*1024; + + public static LinkedList garbageList = new LinkedList(); + + public static void genGarbage() { + for (int i = 0; i < 32*1024; i++) { + garbageList.add(new int[100]); + } + garbageList.clear(); + } + + + // A large object referenced by a static. + static int[] filler = new int[10 * M]; + + // Old gen object referencing the large object, generating remembered + // set entries. + static RefHolder fromOld = new RefHolder(); + + public static void main(String[] args) { + + int[] large = new int[M]; + + Object ref_from_stack = large; + + for (int i = 0; i < 100; i++) { + // A large object that will be reclaimed eagerly. + large = new int[6*M]; + fromOld.ref = large; + genGarbage(); + } + + // Keep the reference to the first object alive. + System.out.println(ref_from_stack); + } +} + +public class TestEagerReclaimHumongousRegionsWithRefs { + + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseG1GC", + "-Xms128M", + "-Xmx128M", + "-Xmn16M", + "-XX:+PrintGC", + ReclaimRegionFast.class.getName()); + + Pattern p = Pattern.compile("Full GC"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + int found = 0; + Matcher m = p.matcher(output.getStdout()); + while (m.find()) { + found++; + } + System.out.println("Issued " + found + " Full GCs"); + + assertLessThan(found, 10, "Found that " + found + " Full GCs were issued. This is larger than the bound. Eager reclaim of objects once referenced from old gen seems to not work at all"); + output.shouldHaveExitValue(0); + } +} +