8027959: Early reclamation of large objects in G1

Wed, 23 Jul 2014 09:03:32 +0200

author
tschatzl
date
Wed, 23 Jul 2014 09:03:32 +0200
changeset 7010
a3953c777565
parent 7009
3f2894c5052e
child 7011
ca8b8e21e2ca

8027959: Early reclamation of large objects in G1
Summary: Try to reclaim humongous objects at every young collection after doing a conservative estimate of its liveness.
Reviewed-by: brutisso, mgerdin

src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1_globals.hpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp file | annotate | diff | comparison | revisions
test/gc/g1/TestEagerReclaimHumongousRegions.java file | annotate | diff | comparison | revisions
test/gc/g1/TestGCLogMessages.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Mon Jul 21 10:00:31 2014 +0200
     1.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp	Wed Jul 23 09:03:32 2014 +0200
     1.3 @@ -1928,6 +1928,8 @@
     1.4    _secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()),
     1.5    _old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()),
     1.6    _humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()),
     1.7 +  _humongous_is_live(),
     1.8 +  _has_humongous_reclaim_candidates(false),
     1.9    _free_regions_coming(false),
    1.10    _young_list(new YoungList(this)),
    1.11    _gc_time_stamp(0),
    1.12 @@ -2084,6 +2086,7 @@
    1.13    _g1h = this;
    1.14  
    1.15    _in_cset_fast_test.initialize(_g1_reserved.start(), _g1_reserved.end(), HeapRegion::GrainBytes);
    1.16 +  _humongous_is_live.initialize(_g1_reserved.start(), _g1_reserved.end(), HeapRegion::GrainBytes);
    1.17  
    1.18    // Create the ConcurrentMark data structure and thread.
    1.19    // (Must do this late, so that "max_regions" is defined.)
    1.20 @@ -2179,6 +2182,11 @@
    1.21    }
    1.22  }
    1.23  
    1.24 +void G1CollectedHeap::clear_humongous_is_live_table() {
    1.25 +  guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true");
    1.26 +  _humongous_is_live.clear();
    1.27 +}
    1.28 +
    1.29  size_t G1CollectedHeap::conservative_max_heap_alignment() {
    1.30    return HeapRegion::max_region_size();
    1.31  }
    1.32 @@ -3797,6 +3805,61 @@
    1.33    return g1_rem_set()->cardsScanned();
    1.34  }
    1.35  
    1.36 +bool G1CollectedHeap::humongous_region_is_always_live(uint index) {
    1.37 +  HeapRegion* region = region_at(index);
    1.38 +  assert(region->startsHumongous(), "Must start a humongous object");
    1.39 +  return oop(region->bottom())->is_objArray() || !region->rem_set()->is_empty();
    1.40 +}
    1.41 +
    1.42 +class RegisterHumongousWithInCSetFastTestClosure : public HeapRegionClosure {
    1.43 + private:
    1.44 +  size_t _total_humongous;
    1.45 +  size_t _candidate_humongous;
    1.46 + public:
    1.47 +  RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) {
    1.48 +  }
    1.49 +
    1.50 +  virtual bool doHeapRegion(HeapRegion* r) {
    1.51 +    if (!r->startsHumongous()) {
    1.52 +      return false;
    1.53 +    }
    1.54 +    G1CollectedHeap* g1h = G1CollectedHeap::heap();
    1.55 +
    1.56 +    uint region_idx = r->hrs_index();
    1.57 +    bool is_candidate = !g1h->humongous_region_is_always_live(region_idx);
    1.58 +    // Is_candidate already filters out humongous regions with some remembered set.
    1.59 +    // This will not lead to humongous object that we mistakenly keep alive because
    1.60 +    // during young collection the remembered sets will only be added to.
    1.61 +    if (is_candidate) {
    1.62 +      g1h->register_humongous_region_with_in_cset_fast_test(region_idx);
    1.63 +      _candidate_humongous++;
    1.64 +    }
    1.65 +    _total_humongous++;
    1.66 +
    1.67 +    return false;
    1.68 +  }
    1.69 +
    1.70 +  size_t total_humongous() const { return _total_humongous; }
    1.71 +  size_t candidate_humongous() const { return _candidate_humongous; }
    1.72 +};
    1.73 +
    1.74 +void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() {
    1.75 +  if (!G1ReclaimDeadHumongousObjectsAtYoungGC) {
    1.76 +    g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0);
    1.77 +    return;
    1.78 +  }
    1.79 +
    1.80 +  RegisterHumongousWithInCSetFastTestClosure cl;
    1.81 +  heap_region_iterate(&cl);
    1.82 +  g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(),
    1.83 +                                                                  cl.candidate_humongous());
    1.84 +  _has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
    1.85 +
    1.86 +  if (_has_humongous_reclaim_candidates) {
    1.87 +    clear_humongous_is_live_table();
    1.88 +  }
    1.89 +}
    1.90 +
    1.91  void
    1.92  G1CollectedHeap::setup_surviving_young_words() {
    1.93    assert(_surviving_young_words == NULL, "pre-condition");
    1.94 @@ -4083,6 +4146,8 @@
    1.95  
    1.96          g1_policy()->finalize_cset(target_pause_time_ms, evacuation_info);
    1.97  
    1.98 +        register_humongous_regions_with_in_cset_fast_test();
    1.99 +
   1.100          _cm->note_start_of_gc();
   1.101          // We should not verify the per-thread SATB buffers given that
   1.102          // we have not filtered them yet (we'll do so during the
   1.103 @@ -4133,6 +4198,9 @@
   1.104                                   true  /* verify_fingers */);
   1.105  
   1.106          free_collection_set(g1_policy()->collection_set(), evacuation_info);
   1.107 +
   1.108 +        eagerly_reclaim_humongous_regions();
   1.109 +
   1.110          g1_policy()->clear_collection_set();
   1.111  
   1.112          cleanup_surviving_young_words();
   1.113 @@ -4644,7 +4712,9 @@
   1.114  
   1.115    assert(_worker_id == _par_scan_state->queue_num(), "sanity");
   1.116  
   1.117 -  if (_g1->in_cset_fast_test(obj)) {
   1.118 +  G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj);
   1.119 +
   1.120 +  if (state == G1CollectedHeap::InCSet) {
   1.121      oop forwardee;
   1.122      if (obj->is_forwarded()) {
   1.123        forwardee = obj->forwardee();
   1.124 @@ -4663,6 +4733,9 @@
   1.125        do_klass_barrier(p, forwardee);
   1.126      }
   1.127    } else {
   1.128 +    if (state == G1CollectedHeap::IsHumongous) {
   1.129 +      _g1->set_humongous_is_live(obj);
   1.130 +    }
   1.131      // The object is not in collection set. If we're a root scanning
   1.132      // closure during an initial mark pause then attempt to mark the object.
   1.133      if (do_mark_object == G1MarkFromRoot) {
   1.134 @@ -5492,12 +5565,21 @@
   1.135  public:
   1.136    G1KeepAliveClosure(G1CollectedHeap* g1) : _g1(g1) {}
   1.137    void do_oop(narrowOop* p) { guarantee(false, "Not needed"); }
   1.138 -  void do_oop(      oop* p) {
   1.139 +  void do_oop(oop* p) {
   1.140      oop obj = *p;
   1.141  
   1.142 -    if (_g1->obj_in_cs(obj)) {
   1.143 +    G1CollectedHeap::in_cset_state_t cset_state = _g1->in_cset_state(obj);
   1.144 +    if (obj == NULL || cset_state == G1CollectedHeap::InNeither) {
   1.145 +      return;
   1.146 +    }
   1.147 +    if (cset_state == G1CollectedHeap::InCSet) {
   1.148        assert( obj->is_forwarded(), "invariant" );
   1.149        *p = obj->forwardee();
   1.150 +    } else {
   1.151 +      assert(!obj->is_forwarded(), "invariant" );
   1.152 +      assert(cset_state == G1CollectedHeap::IsHumongous,
   1.153 +             err_msg("Only allowed InCSet state is IsHumongous, but is %d", cset_state));
   1.154 +      _g1->set_humongous_is_live(obj);
   1.155      }
   1.156    }
   1.157  };
   1.158 @@ -5527,7 +5609,7 @@
   1.159    template <class T> void do_oop_work(T* p) {
   1.160      oop obj = oopDesc::load_decode_heap_oop(p);
   1.161  
   1.162 -    if (_g1h->obj_in_cs(obj)) {
   1.163 +    if (_g1h->is_in_cset_or_humongous(obj)) {
   1.164        // If the referent object has been forwarded (either copied
   1.165        // to a new location or to itself in the event of an
   1.166        // evacuation failure) then we need to update the reference
   1.167 @@ -5552,10 +5634,10 @@
   1.168          assert(!Metaspace::contains((const void*)p),
   1.169                 err_msg("Unexpectedly found a pointer from metadata: "
   1.170                                PTR_FORMAT, p));
   1.171 -          _copy_non_heap_obj_cl->do_oop(p);
   1.172 -        }
   1.173 +        _copy_non_heap_obj_cl->do_oop(p);
   1.174        }
   1.175      }
   1.176 +  }
   1.177  };
   1.178  
   1.179  // Serial drain queue closure. Called as the 'complete_gc'
   1.180 @@ -6477,6 +6559,147 @@
   1.181    policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms);
   1.182  }
   1.183  
   1.184 +class G1FreeHumongousRegionClosure : public HeapRegionClosure {
   1.185 + private:
   1.186 +  FreeRegionList* _free_region_list;
   1.187 +  HeapRegionSet* _proxy_set;
   1.188 +  HeapRegionSetCount _humongous_regions_removed;
   1.189 +  size_t _freed_bytes;
   1.190 + public:
   1.191 +
   1.192 +  G1FreeHumongousRegionClosure(FreeRegionList* free_region_list) :
   1.193 +    _free_region_list(free_region_list), _humongous_regions_removed(), _freed_bytes(0) {
   1.194 +  }
   1.195 +
   1.196 +  virtual bool doHeapRegion(HeapRegion* r) {
   1.197 +    if (!r->startsHumongous()) {
   1.198 +      return false;
   1.199 +    }
   1.200 +
   1.201 +    G1CollectedHeap* g1h = G1CollectedHeap::heap();
   1.202 +
   1.203 +    // The following checks whether the humongous object is live are sufficient.
   1.204 +    // The main additional check (in addition to having a reference from the roots
   1.205 +    // or the young gen) is whether the humongous object has a remembered set entry.
   1.206 +    //
   1.207 +    // A humongous object cannot be live if there is no remembered set for it
   1.208 +    // because:
   1.209 +    // - there can be no references from within humongous starts regions referencing
   1.210 +    // the object because we never allocate other objects into them.
   1.211 +    // (I.e. there are no intra-region references that may be missed by the
   1.212 +    // remembered set)
   1.213 +    // - as soon there is a remembered set entry to the humongous starts region
   1.214 +    // (i.e. it has "escaped" to an old object) this remembered set entry will stay
   1.215 +    // until the end of a concurrent mark.
   1.216 +    //
   1.217 +    // It is not required to check whether the object has been found dead by marking
   1.218 +    // or not, in fact it would prevent reclamation within a concurrent cycle, as
   1.219 +    // all objects allocated during that time are considered live.
   1.220 +    // SATB marking is even more conservative than the remembered set.
   1.221 +    // So if at this point in the collection there is no remembered set entry,
   1.222 +    // nobody has a reference to it.
   1.223 +    // At the start of collection we flush all refinement logs, and remembered sets
   1.224 +    // are completely up-to-date wrt to references to the humongous object.
   1.225 +    //
   1.226 +    // Other implementation considerations:
   1.227 +    // - never consider object arrays: while they are a valid target, they have not
   1.228 +    // been observed to be used as temporary objects.
   1.229 +    // - they would also pose considerable effort for cleaning up the the remembered
   1.230 +    // sets.
   1.231 +    // While this cleanup is not strictly necessary to be done (or done instantly),
   1.232 +    // given that their occurrence is very low, this saves us this additional
   1.233 +    // complexity.
   1.234 +    uint region_idx = r->hrs_index();
   1.235 +    if (g1h->humongous_is_live(region_idx) ||
   1.236 +        g1h->humongous_region_is_always_live(region_idx)) {
   1.237 +
   1.238 +      if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
   1.239 +        gclog_or_tty->print_cr("Live humongous %d region %d with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is dead-bitmap %d live-other %d obj array %d",
   1.240 +                               r->isHumongous(),
   1.241 +                               region_idx,
   1.242 +                               r->rem_set()->occupied(),
   1.243 +                               r->rem_set()->strong_code_roots_list_length(),
   1.244 +                               g1h->mark_in_progress() && !g1h->g1_policy()->during_initial_mark_pause(),
   1.245 +                               g1h->humongous_is_live(region_idx),
   1.246 +                               oop(r->bottom())->is_objArray()
   1.247 +                              );
   1.248 +      }
   1.249 +
   1.250 +      return false;
   1.251 +    }
   1.252 +
   1.253 +    guarantee(!((oop)(r->bottom()))->is_objArray(),
   1.254 +              err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.",
   1.255 +                      r->bottom()));
   1.256 +
   1.257 +    if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
   1.258 +      gclog_or_tty->print_cr("Reclaim humongous region %d start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is dead-bitmap %d live-other %d obj array %d",
   1.259 +                             r->isHumongous(),
   1.260 +                             r->bottom(),
   1.261 +                             region_idx,
   1.262 +                             r->region_num(),
   1.263 +                             r->rem_set()->occupied(),
   1.264 +                             r->rem_set()->strong_code_roots_list_length(),
   1.265 +                             g1h->mark_in_progress() && !g1h->g1_policy()->during_initial_mark_pause(),
   1.266 +                             g1h->humongous_is_live(region_idx),
   1.267 +                             oop(r->bottom())->is_objArray()
   1.268 +                            );
   1.269 +    }
   1.270 +    _freed_bytes += r->used();
   1.271 +    r->set_containing_set(NULL);
   1.272 +    _humongous_regions_removed.increment(1u, r->capacity());
   1.273 +    g1h->free_humongous_region(r, _free_region_list, false);
   1.274 +
   1.275 +    return false;
   1.276 +  }
   1.277 +
   1.278 +  HeapRegionSetCount& humongous_free_count() {
   1.279 +    return _humongous_regions_removed;
   1.280 +  }
   1.281 +
   1.282 +  size_t bytes_freed() const {
   1.283 +    return _freed_bytes;
   1.284 +  }
   1.285 +
   1.286 +  size_t humongous_reclaimed() const {
   1.287 +    return _humongous_regions_removed.length();
   1.288 +  }
   1.289 +};
   1.290 +
   1.291 +void G1CollectedHeap::eagerly_reclaim_humongous_regions() {
   1.292 +  assert_at_safepoint(true);
   1.293 +
   1.294 +  if (!G1ReclaimDeadHumongousObjectsAtYoungGC || !_has_humongous_reclaim_candidates) {
   1.295 +    g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0);
   1.296 +    return;
   1.297 +  }
   1.298 +
   1.299 +  double start_time = os::elapsedTime();
   1.300 +
   1.301 +  FreeRegionList local_cleanup_list("Local Humongous Cleanup List");
   1.302 +
   1.303 +  G1FreeHumongousRegionClosure cl(&local_cleanup_list);
   1.304 +  heap_region_iterate(&cl);
   1.305 +
   1.306 +  HeapRegionSetCount empty_set;
   1.307 +  remove_from_old_sets(empty_set, cl.humongous_free_count());
   1.308 +
   1.309 +  G1HRPrinter* hr_printer = _g1h->hr_printer();
   1.310 +  if (hr_printer->is_active()) {
   1.311 +    FreeRegionListIterator iter(&local_cleanup_list);
   1.312 +    while (iter.more_available()) {
   1.313 +      HeapRegion* hr = iter.get_next();
   1.314 +      hr_printer->cleanup(hr);
   1.315 +    }
   1.316 +  }
   1.317 +
   1.318 +  prepend_to_freelist(&local_cleanup_list);
   1.319 +  decrement_summary_bytes(cl.bytes_freed());
   1.320 +
   1.321 +  g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms((os::elapsedTime() - start_time) * 1000.0,
   1.322 +                                                                    cl.humongous_reclaimed());
   1.323 +}
   1.324 +
   1.325  // This routine is similar to the above but does not record
   1.326  // any policy statistics or update free lists; we are abandoning
   1.327  // the current incremental collection set in preparation of a
     2.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Mon Jul 21 10:00:31 2014 +0200
     2.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp	Wed Jul 23 09:03:32 2014 +0200
     2.3 @@ -197,16 +197,6 @@
     2.4    bool do_object_b(oop p);
     2.5  };
     2.6  
     2.7 -// Instances of this class are used for quick tests on whether a reference points
     2.8 -// into the collection set. Each of the array's elements denotes whether the
     2.9 -// corresponding region is in the collection set.
    2.10 -class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray<bool> {
    2.11 - protected:
    2.12 -  bool default_value() const { return false; }
    2.13 - public:
    2.14 -  void clear() { G1BiasedMappedArray<bool>::clear(); }
    2.15 -};
    2.16 -
    2.17  class RefineCardTableEntryClosure;
    2.18  
    2.19  class G1CollectedHeap : public SharedHeap {
    2.20 @@ -237,6 +227,7 @@
    2.21    friend class EvacPopObjClosure;
    2.22    friend class G1ParCleanupCTTask;
    2.23  
    2.24 +  friend class G1FreeHumongousRegionClosure;
    2.25    // Other related classes.
    2.26    friend class G1MarkSweep;
    2.27  
    2.28 @@ -267,6 +258,9 @@
    2.29    // It keeps track of the humongous regions.
    2.30    HeapRegionSet _humongous_set;
    2.31  
    2.32 +  void clear_humongous_is_live_table();
    2.33 +  void eagerly_reclaim_humongous_regions();
    2.34 +
    2.35    // The number of regions we could create by expansion.
    2.36    uint _expansion_regions;
    2.37  
    2.38 @@ -367,10 +361,25 @@
    2.39    // than the current allocation region.
    2.40    size_t _summary_bytes_used;
    2.41  
    2.42 -  // This array is used for a quick test on whether a reference points into
    2.43 -  // the collection set or not. Each of the array's elements denotes whether the
    2.44 -  // corresponding region is in the collection set or not.
    2.45 -  G1FastCSetBiasedMappedArray _in_cset_fast_test;
    2.46 +  // Records whether the region at the given index is kept live by roots or
    2.47 +  // references from the young generation.
    2.48 +  class HumongousIsLiveBiasedMappedArray : public G1BiasedMappedArray<bool> {
    2.49 +   protected:
    2.50 +    bool default_value() const { return false; }
    2.51 +   public:
    2.52 +    void clear() { G1BiasedMappedArray<bool>::clear(); }
    2.53 +    void set_live(uint region) {
    2.54 +      set_by_index(region, true);
    2.55 +    }
    2.56 +    bool is_live(uint region) {
    2.57 +      return get_by_index(region);
    2.58 +    }
    2.59 +  };
    2.60 +
    2.61 +  HumongousIsLiveBiasedMappedArray _humongous_is_live;
    2.62 +  // Stores whether during humongous object registration we found candidate regions.
    2.63 +  // If not, we can skip a few steps.
    2.64 +  bool _has_humongous_reclaim_candidates;
    2.65  
    2.66    volatile unsigned _gc_time_stamp;
    2.67  
    2.68 @@ -690,10 +699,24 @@
    2.69    virtual void gc_prologue(bool full);
    2.70    virtual void gc_epilogue(bool full);
    2.71  
    2.72 +  inline void set_humongous_is_live(oop obj);
    2.73 +
    2.74 +  bool humongous_is_live(uint region) {
    2.75 +    return _humongous_is_live.is_live(region);
    2.76 +  }
    2.77 +
    2.78 +  // Returns whether the given region (which must be a humongous (start) region)
    2.79 +  // is to be considered conservatively live regardless of any other conditions.
    2.80 +  bool humongous_region_is_always_live(uint index);
    2.81 +  // Register the given region to be part of the collection set.
    2.82 +  inline void register_humongous_region_with_in_cset_fast_test(uint index);
    2.83 +  // Register regions with humongous objects (actually on the start region) in
    2.84 +  // the in_cset_fast_test table.
    2.85 +  void register_humongous_regions_with_in_cset_fast_test();
    2.86    // We register a region with the fast "in collection set" test. We
    2.87    // simply set to true the array slot corresponding to this region.
    2.88    void register_region_with_in_cset_fast_test(HeapRegion* r) {
    2.89 -    _in_cset_fast_test.set_by_index(r->hrs_index(), true);
    2.90 +    _in_cset_fast_test.set_in_cset(r->hrs_index());
    2.91    }
    2.92  
    2.93    // This is a fast test on whether a reference points into the
    2.94 @@ -1292,9 +1315,61 @@
    2.95    virtual bool is_in(const void* p) const;
    2.96  
    2.97    // Return "TRUE" iff the given object address is within the collection
    2.98 -  // set.
    2.99 +  // set. Slow implementation.
   2.100    inline bool obj_in_cs(oop obj);
   2.101  
   2.102 +  inline bool is_in_cset(oop obj);
   2.103 +
   2.104 +  inline bool is_in_cset_or_humongous(const oop obj);
   2.105 +
   2.106 +  enum in_cset_state_t {
   2.107 +   InNeither,           // neither in collection set nor humongous
   2.108 +   InCSet,              // region is in collection set only
   2.109 +   IsHumongous          // region is a humongous start region
   2.110 +  };
   2.111 + private:
   2.112 +  // Instances of this class are used for quick tests on whether a reference points
   2.113 +  // into the collection set or is a humongous object (points into a humongous
   2.114 +  // object).
   2.115 +  // Each of the array's elements denotes whether the corresponding region is in
   2.116 +  // the collection set or a humongous region.
   2.117 +  // We use this to quickly reclaim humongous objects: by making a humongous region
   2.118 +  // succeed this test, we sort-of add it to the collection set. During the reference
   2.119 +  // iteration closures, when we see a humongous region, we simply mark it as
   2.120 +  // referenced, i.e. live.
   2.121 +  class G1FastCSetBiasedMappedArray : public G1BiasedMappedArray<char> {
   2.122 +   protected:
   2.123 +    char default_value() const { return G1CollectedHeap::InNeither; }
   2.124 +   public:
   2.125 +    void set_humongous(uintptr_t index) {
   2.126 +      assert(get_by_index(index) != InCSet, "Should not overwrite InCSet values");
   2.127 +      set_by_index(index, G1CollectedHeap::IsHumongous);
   2.128 +    }
   2.129 +
   2.130 +    void clear_humongous(uintptr_t index) {
   2.131 +      set_by_index(index, G1CollectedHeap::InNeither);
   2.132 +    }
   2.133 +
   2.134 +    void set_in_cset(uintptr_t index) {
   2.135 +      assert(get_by_index(index) != G1CollectedHeap::IsHumongous, "Should not overwrite IsHumongous value");
   2.136 +      set_by_index(index, G1CollectedHeap::InCSet);
   2.137 +    }
   2.138 +
   2.139 +    bool is_in_cset_or_humongous(HeapWord* addr) const { return get_by_address(addr) != G1CollectedHeap::InNeither; }
   2.140 +    bool is_in_cset(HeapWord* addr) const { return get_by_address(addr) == G1CollectedHeap::InCSet; }
   2.141 +    G1CollectedHeap::in_cset_state_t at(HeapWord* addr) const { return (G1CollectedHeap::in_cset_state_t)get_by_address(addr); }
   2.142 +    void clear() { G1BiasedMappedArray<char>::clear(); }
   2.143 +  };
   2.144 +
   2.145 +  // This array is used for a quick test on whether a reference points into
   2.146 +  // the collection set or not. Each of the array's elements denotes whether the
   2.147 +  // corresponding region is in the collection set or not.
   2.148 +  G1FastCSetBiasedMappedArray _in_cset_fast_test;
   2.149 +
   2.150 + public:
   2.151 +
   2.152 +  inline in_cset_state_t in_cset_state(const oop obj);
   2.153 +
   2.154    // Return "TRUE" iff the given object address is in the reserved
   2.155    // region of g1.
   2.156    bool is_in_g1_reserved(const void* p) const {
   2.157 @@ -1349,6 +1424,10 @@
   2.158    // Return the region with the given index. It assumes the index is valid.
   2.159    inline HeapRegion* region_at(uint index) const;
   2.160  
   2.161 +  // Calculate the region index of the given address. Given address must be
   2.162 +  // within the heap.
   2.163 +  inline uint addr_to_region(HeapWord* addr) const;
   2.164 +
   2.165    // Divide the heap region sequence into "chunks" of some size (the number
   2.166    // of regions divided by the number of parallel threads times some
   2.167    // overpartition factor, currently 4).  Assumes that this will be called
     3.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Mon Jul 21 10:00:31 2014 +0200
     3.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp	Wed Jul 23 09:03:32 2014 +0200
     3.3 @@ -40,6 +40,13 @@
     3.4  // Return the region with the given index. It assumes the index is valid.
     3.5  inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrs.at(index); }
     3.6  
     3.7 +inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const {
     3.8 +  assert(is_in_reserved(addr),
     3.9 +         err_msg("Cannot calculate region index for address "PTR_FORMAT" that is outside of the heap ["PTR_FORMAT", "PTR_FORMAT")",
    3.10 +                 p2i(addr), p2i(_reserved.start()), p2i(_reserved.end())));
    3.11 +  return (uint)(pointer_delta(addr, _reserved.start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes);
    3.12 +}
    3.13 +
    3.14  template <class T>
    3.15  inline HeapRegion*
    3.16  G1CollectedHeap::heap_region_containing(const T addr) const {
    3.17 @@ -172,12 +179,11 @@
    3.18    return _cm->nextMarkBitMap()->isMarked((HeapWord *)obj);
    3.19  }
    3.20  
    3.21 -
    3.22  // This is a fast test on whether a reference points into the
    3.23  // collection set or not. Assume that the reference
    3.24  // points into the heap.
    3.25 -inline bool G1CollectedHeap::in_cset_fast_test(oop obj) {
    3.26 -  bool ret = _in_cset_fast_test.get_by_address((HeapWord*)obj);
    3.27 +inline bool G1CollectedHeap::is_in_cset(oop obj) {
    3.28 +  bool ret = _in_cset_fast_test.is_in_cset((HeapWord*)obj);
    3.29    // let's make sure the result is consistent with what the slower
    3.30    // test returns
    3.31    assert( ret || !obj_in_cs(obj), "sanity");
    3.32 @@ -185,6 +191,18 @@
    3.33    return ret;
    3.34  }
    3.35  
    3.36 +bool G1CollectedHeap::is_in_cset_or_humongous(const oop obj) {
    3.37 +  return _in_cset_fast_test.is_in_cset_or_humongous((HeapWord*)obj);
    3.38 +}
    3.39 +
    3.40 +G1CollectedHeap::in_cset_state_t G1CollectedHeap::in_cset_state(const oop obj) {
    3.41 +  return _in_cset_fast_test.at((HeapWord*)obj);
    3.42 +}
    3.43 +
    3.44 +void G1CollectedHeap::register_humongous_region_with_in_cset_fast_test(uint index) {
    3.45 +  _in_cset_fast_test.set_humongous(index);
    3.46 +}
    3.47 +
    3.48  #ifndef PRODUCT
    3.49  // Support for G1EvacuationFailureALot
    3.50  
    3.51 @@ -290,4 +308,22 @@
    3.52    else return is_obj_ill(obj, hr);
    3.53  }
    3.54  
    3.55 +inline void G1CollectedHeap::set_humongous_is_live(oop obj) {
    3.56 +  uint region = addr_to_region((HeapWord*)obj);
    3.57 +  // We not only set the "live" flag in the humongous_is_live table, but also
    3.58 +  // reset the entry in the _in_cset_fast_test table so that subsequent references
    3.59 +  // to the same humongous object do not go into the slow path again.
    3.60 +  // This is racy, as multiple threads may at the same time enter here, but this
    3.61 +  // is benign.
    3.62 +  // During collection we only ever set the "live" flag, and only ever clear the
    3.63 +  // entry in the in_cset_fast_table.
    3.64 +  // We only ever evaluate the contents of these tables (in the VM thread) after
    3.65 +  // having synchronized the worker threads with the VM thread, or in the same
    3.66 +  // thread (i.e. within the VM thread).
    3.67 +  if (!_humongous_is_live.is_live(region)) {
    3.68 +    _humongous_is_live.set_live(region);
    3.69 +    _in_cset_fast_test.clear_humongous(region);
    3.70 +  }
    3.71 +}
    3.72 +
    3.73  #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1COLLECTEDHEAP_INLINE_HPP
     4.1 --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Mon Jul 21 10:00:31 2014 +0200
     4.2 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp	Wed Jul 23 09:03:32 2014 +0200
     4.3 @@ -254,6 +254,10 @@
     4.4    LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value);
     4.5  }
     4.6  
     4.7 +void G1GCPhaseTimes::print_stats(int level, const char* str, size_t value) {
     4.8 +  LineBuffer(level).append_and_print_cr("[%s: "SIZE_FORMAT"]", str, value);
     4.9 +}
    4.10 +
    4.11  void G1GCPhaseTimes::print_stats(int level, const char* str, double value, uint workers) {
    4.12    LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: " UINT32_FORMAT "]", str, value, workers);
    4.13  }
    4.14 @@ -356,6 +360,14 @@
    4.15        _last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards");
    4.16      }
    4.17    }
    4.18 +  if (G1ReclaimDeadHumongousObjectsAtYoungGC) {
    4.19 +    print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
    4.20 +    if (G1Log::finest()) {
    4.21 +      print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total);
    4.22 +      print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
    4.23 +      print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
    4.24 +    }
    4.25 +  }
    4.26    print_stats(2, "Free CSet",
    4.27      (_recorded_young_free_cset_time_ms +
    4.28      _recorded_non_young_free_cset_time_ms));
     5.1 --- a/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Mon Jul 21 10:00:31 2014 +0200
     5.2 +++ b/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp	Wed Jul 23 09:03:32 2014 +0200
     5.3 @@ -157,11 +157,17 @@
     5.4    double _recorded_young_free_cset_time_ms;
     5.5    double _recorded_non_young_free_cset_time_ms;
     5.6  
     5.7 +  double _cur_fast_reclaim_humongous_time_ms;
     5.8 +  size_t _cur_fast_reclaim_humongous_total;
     5.9 +  size_t _cur_fast_reclaim_humongous_candidates;
    5.10 +  size_t _cur_fast_reclaim_humongous_reclaimed;
    5.11 +
    5.12    double _cur_verify_before_time_ms;
    5.13    double _cur_verify_after_time_ms;
    5.14  
    5.15    // Helper methods for detailed logging
    5.16    void print_stats(int level, const char* str, double value);
    5.17 +  void print_stats(int level, const char* str, size_t value);
    5.18    void print_stats(int level, const char* str, double value, uint workers);
    5.19  
    5.20   public:
    5.21 @@ -282,6 +288,16 @@
    5.22      _recorded_non_young_free_cset_time_ms = time_ms;
    5.23    }
    5.24  
    5.25 +  void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) {
    5.26 +    _cur_fast_reclaim_humongous_total = total;
    5.27 +    _cur_fast_reclaim_humongous_candidates = candidates;
    5.28 +  }
    5.29 +
    5.30 +  void record_fast_reclaim_humongous_time_ms(double value, size_t reclaimed) {
    5.31 +    _cur_fast_reclaim_humongous_time_ms = value;
    5.32 +    _cur_fast_reclaim_humongous_reclaimed = reclaimed;
    5.33 +  }
    5.34 +
    5.35    void record_young_cset_choice_time_ms(double time_ms) {
    5.36      _recorded_young_cset_choice_time_ms = time_ms;
    5.37    }
    5.38 @@ -348,6 +364,10 @@
    5.39      return _recorded_non_young_free_cset_time_ms;
    5.40    }
    5.41  
    5.42 +  double fast_reclaim_humongous_time_ms() {
    5.43 +    return _cur_fast_reclaim_humongous_time_ms;
    5.44 +  }
    5.45 +
    5.46    double average_last_update_rs_time() {
    5.47      return _last_update_rs_times_ms.average();
    5.48    }
     6.1 --- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp	Mon Jul 21 10:00:31 2014 +0200
     6.2 +++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp	Wed Jul 23 09:03:32 2014 +0200
     6.3 @@ -44,7 +44,7 @@
     6.4  inline void FilterIntoCSClosure::do_oop_nv(T* p) {
     6.5    T heap_oop = oopDesc::load_heap_oop(p);
     6.6    if (!oopDesc::is_null(heap_oop) &&
     6.7 -      _g1->obj_in_cs(oopDesc::decode_heap_oop_not_null(heap_oop))) {
     6.8 +      _g1->is_in_cset_or_humongous(oopDesc::decode_heap_oop_not_null(heap_oop))) {
     6.9      _oc->do_oop(p);
    6.10    }
    6.11  }
    6.12 @@ -67,7 +67,8 @@
    6.13  
    6.14    if (!oopDesc::is_null(heap_oop)) {
    6.15      oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
    6.16 -    if (_g1->in_cset_fast_test(obj)) {
    6.17 +    G1CollectedHeap::in_cset_state_t state = _g1->in_cset_state(obj);
    6.18 +    if (state == G1CollectedHeap::InCSet) {
    6.19        // We're not going to even bother checking whether the object is
    6.20        // already forwarded or not, as this usually causes an immediate
    6.21        // stall. We'll try to prefetch the object (for write, given that
    6.22 @@ -86,6 +87,9 @@
    6.23  
    6.24        _par_scan_state->push_on_queue(p);
    6.25      } else {
    6.26 +      if (state == G1CollectedHeap::IsHumongous) {
    6.27 +        _g1->set_humongous_is_live(obj);
    6.28 +      }
    6.29        _par_scan_state->update_rs(_from, p, _worker_id);
    6.30      }
    6.31    }
    6.32 @@ -97,12 +101,14 @@
    6.33  
    6.34    if (!oopDesc::is_null(heap_oop)) {
    6.35      oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
    6.36 -    if (_g1->in_cset_fast_test(obj)) {
    6.37 +    if (_g1->is_in_cset_or_humongous(obj)) {
    6.38        Prefetch::write(obj->mark_addr(), 0);
    6.39        Prefetch::read(obj->mark_addr(), (HeapWordSize*2));
    6.40  
    6.41        // Place on the references queue
    6.42        _par_scan_state->push_on_queue(p);
    6.43 +    } else {
    6.44 +      assert(!_g1->obj_in_cs(obj), "checking");
    6.45      }
    6.46    }
    6.47  }
     7.1 --- a/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp	Mon Jul 21 10:00:31 2014 +0200
     7.2 +++ b/src/share/vm/gc_implementation/g1/g1ParScanThreadState.inline.hpp	Wed Jul 23 09:03:32 2014 +0200
     7.3 @@ -52,15 +52,20 @@
     7.4    // set, due to (benign) races in the claim mechanism during RSet scanning more
     7.5    // than one thread might claim the same card. So the same card may be
     7.6    // processed multiple times. So redo this check.
     7.7 -  if (_g1h->in_cset_fast_test(obj)) {
     7.8 +  G1CollectedHeap::in_cset_state_t in_cset_state = _g1h->in_cset_state(obj);
     7.9 +  if (in_cset_state == G1CollectedHeap::InCSet) {
    7.10      oop forwardee;
    7.11      if (obj->is_forwarded()) {
    7.12        forwardee = obj->forwardee();
    7.13      } else {
    7.14        forwardee = copy_to_survivor_space(obj);
    7.15      }
    7.16 -    assert(forwardee != NULL, "forwardee should not be NULL");
    7.17      oopDesc::encode_store_heap_oop(p, forwardee);
    7.18 +  } else if (in_cset_state == G1CollectedHeap::IsHumongous) {
    7.19 +    _g1h->set_humongous_is_live(obj);
    7.20 +  } else {
    7.21 +    assert(in_cset_state == G1CollectedHeap::InNeither,
    7.22 +           err_msg("In_cset_state must be InNeither here, but is %d", in_cset_state));
    7.23    }
    7.24  
    7.25    assert(obj != NULL, "Must be");
     8.1 --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp	Mon Jul 21 10:00:31 2014 +0200
     8.2 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp	Wed Jul 23 09:03:32 2014 +0200
     8.3 @@ -289,6 +289,13 @@
     8.4            "The amount of code root chunks that should be kept at most "     \
     8.5            "as percentage of already allocated.")                            \
     8.6                                                                              \
     8.7 +  experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true,          \
     8.8 +          "Try to reclaim dead large objects at every young GC.")           \
     8.9 +                                                                            \
    8.10 +  experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, false,    \
    8.11 +          "Print some information about large object liveness "             \
    8.12 +          "at every young GC.")                                             \
    8.13 +                                                                            \
    8.14    experimental(uintx, G1OldCSetRegionThresholdPercent, 10,                  \
    8.15            "An upper bound for the number of old CSet regions expressed "    \
    8.16            "as a percentage of the heap size.")                              \
     9.1 --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Mon Jul 21 10:00:31 2014 +0200
     9.2 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp	Wed Jul 23 09:03:32 2014 +0200
     9.3 @@ -694,6 +694,9 @@
     9.4    clear_fcc();
     9.5  }
     9.6  
     9.7 +bool OtherRegionsTable::is_empty() const {
     9.8 +  return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
     9.9 +}
    9.10  
    9.11  size_t OtherRegionsTable::occupied() const {
    9.12    size_t sum = occ_fine();
    10.1 --- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Mon Jul 21 10:00:31 2014 +0200
    10.2 +++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp	Wed Jul 23 09:03:32 2014 +0200
    10.3 @@ -185,6 +185,9 @@
    10.4    // objects.
    10.5    void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
    10.6  
    10.7 +  // Returns whether this remembered set (and all sub-sets) contain no entries.
    10.8 +  bool is_empty() const;
    10.9 +
   10.10    size_t occupied() const;
   10.11    size_t occ_fine() const;
   10.12    size_t occ_coarse() const;
   10.13 @@ -269,6 +272,10 @@
   10.14      return _other_regions.hr();
   10.15    }
   10.16  
   10.17 +  bool is_empty() const {
   10.18 +    return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
   10.19 +  }
   10.20 +
   10.21    size_t occupied() {
   10.22      MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
   10.23      return occupied_locked();
   10.24 @@ -375,7 +382,7 @@
   10.25    void strong_code_roots_do(CodeBlobClosure* blk) const;
   10.26  
   10.27    // Returns the number of elements in the strong code roots list
   10.28 -  size_t strong_code_roots_list_length() {
   10.29 +  size_t strong_code_roots_list_length() const {
   10.30      return _code_roots.length();
   10.31    }
   10.32  
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/test/gc/g1/TestEagerReclaimHumongousRegions.java	Wed Jul 23 09:03:32 2014 +0200
    11.3 @@ -0,0 +1,98 @@
    11.4 +/*
    11.5 + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
    11.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    11.7 + *
    11.8 + * This code is free software; you can redistribute it and/or modify it
    11.9 + * under the terms of the GNU General Public License version 2 only, as
   11.10 + * published by the Free Software Foundation.
   11.11 + *
   11.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   11.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   11.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   11.15 + * version 2 for more details (a copy is included in the LICENSE file that
   11.16 + * accompanied this code).
   11.17 + *
   11.18 + * You should have received a copy of the GNU General Public License version
   11.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   11.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   11.21 + *
   11.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   11.23 + * or visit www.oracle.com if you need additional information or have any
   11.24 + * questions.
   11.25 + */
   11.26 +
   11.27 +/*
   11.28 + * @test TestEagerReclaimHumongousRegions
   11.29 + * @bug 8027959
   11.30 + * @summary Test to make sure that eager reclaim of humongous objects work. We simply try to fill
   11.31 + * up the heap with humongous objects that should be eagerly reclaimable to avoid Full GC.
   11.32 + * @key gc
   11.33 + * @library /testlibrary
   11.34 + */
   11.35 +
   11.36 +import java.util.regex.Pattern;
   11.37 +import java.util.regex.Matcher;
   11.38 +import java.util.LinkedList;
   11.39 +
   11.40 +import com.oracle.java.testlibrary.OutputAnalyzer;
   11.41 +import com.oracle.java.testlibrary.ProcessTools;
   11.42 +import com.oracle.java.testlibrary.Asserts;
   11.43 +
   11.44 +class ReclaimRegionFast {
   11.45 +    public static final int M = 1024*1024;
   11.46 +
   11.47 +    public static LinkedList<Object> garbageList = new LinkedList<Object>();
   11.48 +
   11.49 +    public static void genGarbage() {
   11.50 +        for (int i = 0; i < 32*1024; i++) {
   11.51 +            garbageList.add(new int[100]);
   11.52 +        }
   11.53 +        garbageList.clear();
   11.54 +    }
   11.55 +
   11.56 +    // A large object referenced by a static.
   11.57 +    static int[] filler = new int[10 * M];
   11.58 +
   11.59 +    public static void main(String[] args) {
   11.60 +
   11.61 +        int[] large = new int[M];
   11.62 +
   11.63 +        Object ref_from_stack = large;
   11.64 +
   11.65 +        for (int i = 0; i < 100; i++) {
   11.66 +            // A large object that will be reclaimed eagerly.
   11.67 +            large = new int[6*M];
   11.68 +            genGarbage();
   11.69 +            // Make sure that the compiler cannot completely remove
   11.70 +            // the allocation of the large object until here.
   11.71 +            System.out.println(large);
   11.72 +        }
   11.73 +
   11.74 +        // Keep the reference to the first object alive.
   11.75 +        System.out.println(ref_from_stack);
   11.76 +    }
   11.77 +}
   11.78 +
   11.79 +public class TestEagerReclaimHumongousRegions {
   11.80 +    public static void main(String[] args) throws Exception {
   11.81 +        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
   11.82 +            "-XX:+UseG1GC",
   11.83 +            "-Xms128M",
   11.84 +            "-Xmx128M",
   11.85 +            "-Xmn16M",
   11.86 +            "-XX:+PrintGC",
   11.87 +            ReclaimRegionFast.class.getName());
   11.88 +
   11.89 +        Pattern p = Pattern.compile("Full GC");
   11.90 +
   11.91 +        OutputAnalyzer output = new OutputAnalyzer(pb.start());
   11.92 +
   11.93 +        int found = 0;
   11.94 +        Matcher m = p.matcher(output.getStdout());
   11.95 +        while (m.find()) { found++; }
   11.96 +        System.out.println("Issued " + found + " Full GCs");
   11.97 +        Asserts.assertLT(found, 10, "Found that " + found + " Full GCs were issued. This is larger than the bound. Eager reclaim seems to not work at all");
   11.98 +
   11.99 +        output.shouldHaveExitValue(0);
  11.100 +    }
  11.101 +}
    12.1 --- a/test/gc/g1/TestGCLogMessages.java	Mon Jul 21 10:00:31 2014 +0200
    12.2 +++ b/test/gc/g1/TestGCLogMessages.java	Wed Jul 23 09:03:32 2014 +0200
    12.3 @@ -23,7 +23,7 @@
    12.4  
    12.5  /*
    12.6   * @test TestGCLogMessages
    12.7 - * @bug 8035406 8027295 8035398 8019342
    12.8 + * @bug 8035406 8027295 8035398 8019342 8027959
    12.9   * @summary Ensure that the PrintGCDetails output for a minor GC with G1
   12.10   * includes the expected necessary messages.
   12.11   * @key gc
   12.12 @@ -54,6 +54,7 @@
   12.13      output.shouldNotContain("[String Dedup Fixup");
   12.14      output.shouldNotContain("[Young Free CSet");
   12.15      output.shouldNotContain("[Non-Young Free CSet");
   12.16 +    output.shouldNotContain("[Humongous Reclaim");
   12.17      output.shouldHaveExitValue(0);
   12.18  
   12.19      pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
   12.20 @@ -71,6 +72,10 @@
   12.21      output.shouldContain("[String Dedup Fixup");
   12.22      output.shouldNotContain("[Young Free CSet");
   12.23      output.shouldNotContain("[Non-Young Free CSet");
   12.24 +    output.shouldContain("[Humongous Reclaim");
   12.25 +    output.shouldNotContain("[Humongous Total");
   12.26 +    output.shouldNotContain("[Humongous Candidate");
   12.27 +    output.shouldNotContain("[Humongous Reclaimed");
   12.28      output.shouldHaveExitValue(0);
   12.29  
   12.30      pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
   12.31 @@ -90,6 +95,10 @@
   12.32      output.shouldContain("[String Dedup Fixup");
   12.33      output.shouldContain("[Young Free CSet");
   12.34      output.shouldContain("[Non-Young Free CSet");
   12.35 +    output.shouldContain("[Humongous Reclaim");
   12.36 +    output.shouldContain("[Humongous Total");
   12.37 +    output.shouldContain("[Humongous Candidate");
   12.38 +    output.shouldContain("[Humongous Reclaimed");
   12.39      output.shouldHaveExitValue(0);
   12.40    }
   12.41  

mercurial