Mercurial > hg > truffle
comparison src/share/vm/gc_implementation/g1/g1RemSet.cpp @ 10246:194f52aa2f23
7176479: G1: JVM crashes on T5-8 system with 1.5 TB heap
Summary: Refactor G1's hot card cache and card counts table into their own files. Simplify the card counts table, including removing the encoding of the card index in each entry. The card counts table now has a 1:1 correspondence with the cards spanned by heap. Space for the card counts table is reserved from virtual memory (rather than C heap) during JVM startup and is committed/expanded when the heap is expanded. Changes were also reviewed-by Vitaly Davidovich.
Reviewed-by: tschatzl, jmasa
author | johnc |
---|---|
date | Thu, 09 May 2013 11:16:39 -0700 |
parents | 5c93c1f61226 |
children | e72f7eecc96d |
comparison
equal
deleted
inserted
replaced
10245:923ac8d1df95 | 10246:194f52aa2f23 |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. | 2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | 4 * |
5 * This code is free software; you can redistribute it and/or modify it | 5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as | 6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
27 #include "gc_implementation/g1/concurrentG1Refine.hpp" | 27 #include "gc_implementation/g1/concurrentG1Refine.hpp" |
28 #include "gc_implementation/g1/concurrentG1RefineThread.hpp" | 28 #include "gc_implementation/g1/concurrentG1RefineThread.hpp" |
29 #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" | 29 #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" |
30 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" | 30 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" |
31 #include "gc_implementation/g1/g1CollectorPolicy.hpp" | 31 #include "gc_implementation/g1/g1CollectorPolicy.hpp" |
32 #include "gc_implementation/g1/g1HotCardCache.hpp" | |
32 #include "gc_implementation/g1/g1GCPhaseTimes.hpp" | 33 #include "gc_implementation/g1/g1GCPhaseTimes.hpp" |
33 #include "gc_implementation/g1/g1OopClosures.inline.hpp" | 34 #include "gc_implementation/g1/g1OopClosures.inline.hpp" |
34 #include "gc_implementation/g1/g1RemSet.inline.hpp" | 35 #include "gc_implementation/g1/g1RemSet.inline.hpp" |
35 #include "gc_implementation/g1/heapRegionSeq.inline.hpp" | 36 #include "gc_implementation/g1/heapRegionSeq.inline.hpp" |
36 #include "memory/iterator.hpp" | 37 #include "memory/iterator.hpp" |
245 // is during RSet updating within an evacuation pause. | 246 // is during RSet updating within an evacuation pause. |
246 // In this case worker_i should be the id of a GC worker thread. | 247 // In this case worker_i should be the id of a GC worker thread. |
247 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); | 248 assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); |
248 assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker"); | 249 assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker"); |
249 | 250 |
250 if (_g1rs->concurrentRefineOneCard(card_ptr, worker_i, true)) { | 251 if (_g1rs->refine_card(card_ptr, worker_i, true)) { |
251 // 'card_ptr' contains references that point into the collection | 252 // 'card_ptr' contains references that point into the collection |
252 // set. We need to record the card in the DCQS | 253 // set. We need to record the card in the DCQS |
253 // (G1CollectedHeap::into_cset_dirty_card_queue_set()) | 254 // (G1CollectedHeap::into_cset_dirty_card_queue_set()) |
254 // that's used for that purpose. | 255 // that's used for that purpose. |
255 // | 256 // |
286 void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, | 287 void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, |
287 int worker_i) { | 288 int worker_i) { |
288 #if CARD_REPEAT_HISTO | 289 #if CARD_REPEAT_HISTO |
289 ct_freq_update_histo_and_reset(); | 290 ct_freq_update_histo_and_reset(); |
290 #endif | 291 #endif |
291 if (worker_i == 0) { | |
292 _cg1r->clear_and_record_card_counts(); | |
293 } | |
294 | 292 |
295 // We cache the value of 'oc' closure into the appropriate slot in the | 293 // We cache the value of 'oc' closure into the appropriate slot in the |
296 // _cset_rs_update_cl for this worker | 294 // _cset_rs_update_cl for this worker |
297 assert(worker_i < (int)n_workers(), "sanity"); | 295 assert(worker_i < (int)n_workers(), "sanity"); |
298 _cset_rs_update_cl[worker_i] = oc; | 296 _cset_rs_update_cl[worker_i] = oc; |
394 // * the DCQS to which this closure is applied is used to hold | 392 // * the DCQS to which this closure is applied is used to hold |
395 // references that point into the collection set from the prior | 393 // references that point into the collection set from the prior |
396 // RSet updating, | 394 // RSet updating, |
397 // * the post-write barrier shouldn't be logging updates to young | 395 // * the post-write barrier shouldn't be logging updates to young |
398 // regions (but there is a situation where this can happen - see | 396 // regions (but there is a situation where this can happen - see |
399 // the comment in G1RemSet::concurrentRefineOneCard below - | 397 // the comment in G1RemSet::refine_card() below - |
400 // that should not be applicable here), and | 398 // that should not be applicable here), and |
401 // * during actual RSet updating, the filtering of cards in young | 399 // * during actual RSet updating, the filtering of cards in young |
402 // regions in HeapRegion::oops_on_card_seq_iterate_careful is | 400 // regions in HeapRegion::oops_on_card_seq_iterate_careful is |
403 // employed. | 401 // employed. |
404 // As a result, when this closure is applied to "refs into cset" | 402 // As a result, when this closure is applied to "refs into cset" |
500 worker_num, | 498 worker_num, |
501 n_workers(), | 499 n_workers(), |
502 claim_val); | 500 claim_val); |
503 } | 501 } |
504 | 502 |
505 | |
506 | |
507 G1TriggerClosure::G1TriggerClosure() : | 503 G1TriggerClosure::G1TriggerClosure() : |
508 _triggered(false) { } | 504 _triggered(false) { } |
509 | 505 |
510 G1InvokeIfNotTriggeredClosure::G1InvokeIfNotTriggeredClosure(G1TriggerClosure* t_cl, | 506 G1InvokeIfNotTriggeredClosure::G1InvokeIfNotTriggeredClosure(G1TriggerClosure* t_cl, |
511 OopClosure* oop_cl) : | 507 OopClosure* oop_cl) : |
522 int worker_i) : | 518 int worker_i) : |
523 _g1(g1h), _g1_rem_set(rs), _from(NULL), | 519 _g1(g1h), _g1_rem_set(rs), _from(NULL), |
524 _record_refs_into_cset(record_refs_into_cset), | 520 _record_refs_into_cset(record_refs_into_cset), |
525 _push_ref_cl(push_ref_cl), _worker_i(worker_i) { } | 521 _push_ref_cl(push_ref_cl), _worker_i(worker_i) { } |
526 | 522 |
527 bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i, | 523 // Returns true if the given card contains references that point |
528 bool check_for_refs_into_cset) { | 524 // into the collection set, if we're checking for such references; |
525 // false otherwise. | |
526 | |
527 bool G1RemSet::refine_card(jbyte* card_ptr, int worker_i, | |
528 bool check_for_refs_into_cset) { | |
529 | |
530 // If the card is no longer dirty, nothing to do. | |
531 if (*card_ptr != CardTableModRefBS::dirty_card_val()) { | |
532 // No need to return that this card contains refs that point | |
533 // into the collection set. | |
534 return false; | |
535 } | |
536 | |
529 // Construct the region representing the card. | 537 // Construct the region representing the card. |
530 HeapWord* start = _ct_bs->addr_for(card_ptr); | 538 HeapWord* start = _ct_bs->addr_for(card_ptr); |
531 // And find the region containing it. | 539 // And find the region containing it. |
532 HeapRegion* r = _g1->heap_region_containing(start); | 540 HeapRegion* r = _g1->heap_region_containing(start); |
533 assert(r != NULL, "unexpected null"); | 541 if (r == NULL) { |
542 // Again no need to return that this card contains refs that | |
543 // point into the collection set. | |
544 return false; // Not in the G1 heap (might be in perm, for example.) | |
545 } | |
546 | |
547 // Why do we have to check here whether a card is on a young region, | |
548 // given that we dirty young regions and, as a result, the | |
549 // post-barrier is supposed to filter them out and never to enqueue | |
550 // them? When we allocate a new region as the "allocation region" we | |
551 // actually dirty its cards after we release the lock, since card | |
552 // dirtying while holding the lock was a performance bottleneck. So, | |
553 // as a result, it is possible for other threads to actually | |
554 // allocate objects in the region (after the acquire the lock) | |
555 // before all the cards on the region are dirtied. This is unlikely, | |
556 // and it doesn't happen often, but it can happen. So, the extra | |
557 // check below filters out those cards. | |
558 if (r->is_young()) { | |
559 return false; | |
560 } | |
561 | |
562 // While we are processing RSet buffers during the collection, we | |
563 // actually don't want to scan any cards on the collection set, | |
564 // since we don't want to update remebered sets with entries that | |
565 // point into the collection set, given that live objects from the | |
566 // collection set are about to move and such entries will be stale | |
567 // very soon. This change also deals with a reliability issue which | |
568 // involves scanning a card in the collection set and coming across | |
569 // an array that was being chunked and looking malformed. Note, | |
570 // however, that if evacuation fails, we have to scan any objects | |
571 // that were not moved and create any missing entries. | |
572 if (r->in_collection_set()) { | |
573 return false; | |
574 } | |
575 | |
576 // The result from the hot card cache insert call is either: | |
577 // * pointer to the current card | |
578 // (implying that the current card is not 'hot'), | |
579 // * null | |
580 // (meaning we had inserted the card ptr into the "hot" card cache, | |
581 // which had some headroom), | |
582 // * a pointer to a "hot" card that was evicted from the "hot" cache. | |
583 // | |
584 | |
585 G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache(); | |
586 if (hot_card_cache->use_cache()) { | |
587 assert(!check_for_refs_into_cset, "sanity"); | |
588 assert(!SafepointSynchronize::is_at_safepoint(), "sanity"); | |
589 | |
590 card_ptr = hot_card_cache->insert(card_ptr); | |
591 if (card_ptr == NULL) { | |
592 // There was no eviction. Nothing to do. | |
593 return false; | |
594 } | |
595 | |
596 start = _ct_bs->addr_for(card_ptr); | |
597 r = _g1->heap_region_containing(start); | |
598 if (r == NULL) { | |
599 // Not in the G1 heap | |
600 return false; | |
601 } | |
602 | |
603 // Checking whether the region we got back from the cache | |
604 // is young here is inappropriate. The region could have been | |
605 // freed, reallocated and tagged as young while in the cache. | |
606 // Hence we could see its young type change at any time. | |
607 } | |
534 | 608 |
535 // Don't use addr_for(card_ptr + 1) which can ask for | 609 // Don't use addr_for(card_ptr + 1) which can ask for |
536 // a card beyond the heap. This is not safe without a perm | 610 // a card beyond the heap. This is not safe without a perm |
537 // gen at the upper end of the heap. | 611 // gen at the upper end of the heap. |
538 HeapWord* end = start + CardTableModRefBS::card_size_in_words; | 612 HeapWord* end = start + CardTableModRefBS::card_size_in_words; |
608 } | 682 } |
609 } else { | 683 } else { |
610 _conc_refine_cards++; | 684 _conc_refine_cards++; |
611 } | 685 } |
612 | 686 |
613 return trigger_cl.triggered(); | 687 // This gets set to true if the card being refined has |
614 } | 688 // references that point into the collection set. |
615 | 689 bool has_refs_into_cset = trigger_cl.triggered(); |
616 bool G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i, | 690 |
617 bool check_for_refs_into_cset) { | 691 // We should only be detecting that the card contains references |
618 // If the card is no longer dirty, nothing to do. | 692 // that point into the collection set if the current thread is |
619 if (*card_ptr != CardTableModRefBS::dirty_card_val()) { | 693 // a GC worker thread. |
620 // No need to return that this card contains refs that point | 694 assert(!has_refs_into_cset || SafepointSynchronize::is_at_safepoint(), |
621 // into the collection set. | |
622 return false; | |
623 } | |
624 | |
625 // Construct the region representing the card. | |
626 HeapWord* start = _ct_bs->addr_for(card_ptr); | |
627 // And find the region containing it. | |
628 HeapRegion* r = _g1->heap_region_containing(start); | |
629 if (r == NULL) { | |
630 // Again no need to return that this card contains refs that | |
631 // point into the collection set. | |
632 return false; // Not in the G1 heap (might be in perm, for example.) | |
633 } | |
634 // Why do we have to check here whether a card is on a young region, | |
635 // given that we dirty young regions and, as a result, the | |
636 // post-barrier is supposed to filter them out and never to enqueue | |
637 // them? When we allocate a new region as the "allocation region" we | |
638 // actually dirty its cards after we release the lock, since card | |
639 // dirtying while holding the lock was a performance bottleneck. So, | |
640 // as a result, it is possible for other threads to actually | |
641 // allocate objects in the region (after the acquire the lock) | |
642 // before all the cards on the region are dirtied. This is unlikely, | |
643 // and it doesn't happen often, but it can happen. So, the extra | |
644 // check below filters out those cards. | |
645 if (r->is_young()) { | |
646 return false; | |
647 } | |
648 // While we are processing RSet buffers during the collection, we | |
649 // actually don't want to scan any cards on the collection set, | |
650 // since we don't want to update remebered sets with entries that | |
651 // point into the collection set, given that live objects from the | |
652 // collection set are about to move and such entries will be stale | |
653 // very soon. This change also deals with a reliability issue which | |
654 // involves scanning a card in the collection set and coming across | |
655 // an array that was being chunked and looking malformed. Note, | |
656 // however, that if evacuation fails, we have to scan any objects | |
657 // that were not moved and create any missing entries. | |
658 if (r->in_collection_set()) { | |
659 return false; | |
660 } | |
661 | |
662 // Should we defer processing the card? | |
663 // | |
664 // Previously the result from the insert_cache call would be | |
665 // either card_ptr (implying that card_ptr was currently "cold"), | |
666 // null (meaning we had inserted the card ptr into the "hot" | |
667 // cache, which had some headroom), or a "hot" card ptr | |
668 // extracted from the "hot" cache. | |
669 // | |
670 // Now that the _card_counts cache in the ConcurrentG1Refine | |
671 // instance is an evicting hash table, the result we get back | |
672 // could be from evicting the card ptr in an already occupied | |
673 // bucket (in which case we have replaced the card ptr in the | |
674 // bucket with card_ptr and "defer" is set to false). To avoid | |
675 // having a data structure (updates to which would need a lock) | |
676 // to hold these unprocessed dirty cards, we need to immediately | |
677 // process card_ptr. The actions needed to be taken on return | |
678 // from cache_insert are summarized in the following table: | |
679 // | |
680 // res defer action | |
681 // -------------------------------------------------------------- | |
682 // null false card evicted from _card_counts & replaced with | |
683 // card_ptr; evicted ptr added to hot cache. | |
684 // No need to process res; immediately process card_ptr | |
685 // | |
686 // null true card not evicted from _card_counts; card_ptr added | |
687 // to hot cache. | |
688 // Nothing to do. | |
689 // | |
690 // non-null false card evicted from _card_counts & replaced with | |
691 // card_ptr; evicted ptr is currently "cold" or | |
692 // caused an eviction from the hot cache. | |
693 // Immediately process res; process card_ptr. | |
694 // | |
695 // non-null true card not evicted from _card_counts; card_ptr is | |
696 // currently cold, or caused an eviction from hot | |
697 // cache. | |
698 // Immediately process res; no need to process card_ptr. | |
699 | |
700 | |
701 jbyte* res = card_ptr; | |
702 bool defer = false; | |
703 | |
704 // This gets set to true if the card being refined has references | |
705 // that point into the collection set. | |
706 bool oops_into_cset = false; | |
707 | |
708 if (_cg1r->use_cache()) { | |
709 jbyte* res = _cg1r->cache_insert(card_ptr, &defer); | |
710 if (res != NULL && (res != card_ptr || defer)) { | |
711 start = _ct_bs->addr_for(res); | |
712 r = _g1->heap_region_containing(start); | |
713 if (r != NULL) { | |
714 // Checking whether the region we got back from the cache | |
715 // is young here is inappropriate. The region could have been | |
716 // freed, reallocated and tagged as young while in the cache. | |
717 // Hence we could see its young type change at any time. | |
718 // | |
719 // Process card pointer we get back from the hot card cache. This | |
720 // will check whether the region containing the card is young | |
721 // _after_ checking that the region has been allocated from. | |
722 oops_into_cset = concurrentRefineOneCard_impl(res, worker_i, | |
723 false /* check_for_refs_into_cset */); | |
724 // The above call to concurrentRefineOneCard_impl is only | |
725 // performed if the hot card cache is enabled. This cache is | |
726 // disabled during an evacuation pause - which is the only | |
727 // time when we need know if the card contains references | |
728 // that point into the collection set. Also when the hot card | |
729 // cache is enabled, this code is executed by the concurrent | |
730 // refine threads - rather than the GC worker threads - and | |
731 // concurrentRefineOneCard_impl will return false. | |
732 assert(!oops_into_cset, "should not see true here"); | |
733 } | |
734 } | |
735 } | |
736 | |
737 if (!defer) { | |
738 oops_into_cset = | |
739 concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset); | |
740 // We should only be detecting that the card contains references | |
741 // that point into the collection set if the current thread is | |
742 // a GC worker thread. | |
743 assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(), | |
744 "invalid result at non safepoint"); | 695 "invalid result at non safepoint"); |
745 } | 696 |
746 return oops_into_cset; | 697 return has_refs_into_cset; |
747 } | 698 } |
748 | 699 |
749 class HRRSStatsIter: public HeapRegionClosure { | 700 class HRRSStatsIter: public HeapRegionClosure { |
750 size_t _occupied; | 701 size_t _occupied; |
751 size_t _total_mem_sz; | 702 size_t _total_mem_sz; |
844 _g1->set_refine_cte_cl_concurrency(false); | 795 _g1->set_refine_cte_cl_concurrency(false); |
845 if (SafepointSynchronize::is_at_safepoint()) { | 796 if (SafepointSynchronize::is_at_safepoint()) { |
846 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); | 797 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); |
847 dcqs.concatenate_logs(); | 798 dcqs.concatenate_logs(); |
848 } | 799 } |
849 bool cg1r_use_cache = _cg1r->use_cache(); | 800 |
850 _cg1r->set_use_cache(false); | 801 G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache(); |
802 bool use_hot_card_cache = hot_card_cache->use_cache(); | |
803 hot_card_cache->set_use_cache(false); | |
804 | |
851 DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); | 805 DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); |
852 updateRS(&into_cset_dcq, 0); | 806 updateRS(&into_cset_dcq, 0); |
853 _g1->into_cset_dirty_card_queue_set().clear(); | 807 _g1->into_cset_dirty_card_queue_set().clear(); |
854 _cg1r->set_use_cache(cg1r_use_cache); | 808 |
855 | 809 hot_card_cache->set_use_cache(use_hot_card_cache); |
856 assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); | 810 assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); |
857 } | 811 } |
858 } | 812 } |