src/share/vm/gc_implementation/g1/sparsePRT.cpp

Tue, 27 Oct 2009 02:42:24 -0700

author
apetrusenko
date
Tue, 27 Oct 2009 02:42:24 -0700
changeset 1480
fa2f65ebeb08
parent 1377
2c79770d1f6e
child 1696
0414c1049f15
permissions
-rw-r--r--

6870843: G1: G1 GC memory leak
Summary: The fix addresses two memory leaks in G1 code: (1) _evac_failure_scan_stack - a resource object allocated on the C heap was not freed; (2) RSHashTable were linked into deleted list which was only cleared at full GC.
Reviewed-by: tonyp, iveresov

     1 /*
     2  * Copyright 2001-2009 Sun Microsystems, Inc.  All Rights Reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     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
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    20  * CA 95054 USA or visit www.sun.com if you need additional information or
    21  * have any questions.
    22  *
    23  */
    25 #include "incls/_precompiled.incl"
    26 #include "incls/_sparsePRT.cpp.incl"
    28 #define SPARSE_PRT_VERBOSE 0
    30 #define UNROLL_CARD_LOOPS 1
    32 void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) {
    33     sprt_iter->init(this);
    34 }
    36 void SparsePRTEntry::init(RegionIdx_t region_ind) {
    37   _region_ind = region_ind;
    38   _next_index = NullEntry;
    39 #if UNROLL_CARD_LOOPS
    40   assert(CardsPerEntry == 4, "Assumption.  If changes, un-unroll.");
    41   _cards[0] = NullEntry;
    42   _cards[1] = NullEntry;
    43   _cards[2] = NullEntry;
    44   _cards[3] = NullEntry;
    45 #else
    46   for (int i = 0; i < CardsPerEntry; i++)
    47     _cards[i] = NullEntry;
    48 #endif
    49 }
    51 bool SparsePRTEntry::contains_card(CardIdx_t card_index) const {
    52 #if UNROLL_CARD_LOOPS
    53   assert(CardsPerEntry == 4, "Assumption.  If changes, un-unroll.");
    54   if (_cards[0] == card_index) return true;
    55   if (_cards[1] == card_index) return true;
    56   if (_cards[2] == card_index) return true;
    57   if (_cards[3] == card_index) return true;
    58 #else
    59   for (int i = 0; i < CardsPerEntry; i++) {
    60     if (_cards[i] == card_index) return true;
    61   }
    62 #endif
    63   // Otherwise, we're full.
    64   return false;
    65 }
    67 int SparsePRTEntry::num_valid_cards() const {
    68   int sum = 0;
    69 #if UNROLL_CARD_LOOPS
    70   assert(CardsPerEntry == 4, "Assumption.  If changes, un-unroll.");
    71   if (_cards[0] != NullEntry) sum++;
    72   if (_cards[1] != NullEntry) sum++;
    73   if (_cards[2] != NullEntry) sum++;
    74   if (_cards[3] != NullEntry) sum++;
    75 #else
    76   for (int i = 0; i < CardsPerEntry; i++) {
    77     if (_cards[i] != NulLEntry) sum++;
    78   }
    79 #endif
    80   // Otherwise, we're full.
    81   return sum;
    82 }
    84 SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) {
    85 #if UNROLL_CARD_LOOPS
    86   assert(CardsPerEntry == 4, "Assumption.  If changes, un-unroll.");
    87   CardIdx_t c = _cards[0];
    88   if (c == card_index) return found;
    89   if (c == NullEntry) { _cards[0] = card_index; return added; }
    90   c = _cards[1];
    91   if (c == card_index) return found;
    92   if (c == NullEntry) { _cards[1] = card_index; return added; }
    93   c = _cards[2];
    94   if (c == card_index) return found;
    95   if (c == NullEntry) { _cards[2] = card_index; return added; }
    96   c = _cards[3];
    97   if (c == card_index) return found;
    98   if (c == NullEntry) { _cards[3] = card_index; return added; }
    99 #else
   100   for (int i = 0; i < CardsPerEntry; i++) {
   101     CardIdx_t c = _cards[i];
   102     if (c == card_index) return found;
   103     if (c == NullEntry) {
   104       _cards[i] = card_index;
   105       return added;
   106     }
   107   }
   108 #endif
   109   // Otherwise, we're full.
   110   return overflow;
   111 }
   113 void SparsePRTEntry::copy_cards(CardIdx_t* cards) const {
   114 #if UNROLL_CARD_LOOPS
   115   assert(CardsPerEntry == 4, "Assumption.  If changes, un-unroll.");
   116   cards[0] = _cards[0];
   117   cards[1] = _cards[1];
   118   cards[2] = _cards[2];
   119   cards[3] = _cards[3];
   120 #else
   121   for (int i = 0; i < CardsPerEntry; i++) {
   122     cards[i] = _cards[i];
   123   }
   124 #endif
   125 }
   127 void SparsePRTEntry::copy_cards(SparsePRTEntry* e) const {
   128   copy_cards(&e->_cards[0]);
   129 }
   131 // ----------------------------------------------------------------------
   133 RSHashTable::RSHashTable(size_t capacity) :
   134   _capacity(capacity), _capacity_mask(capacity-1),
   135   _occupied_entries(0), _occupied_cards(0),
   136   _entries(NEW_C_HEAP_ARRAY(SparsePRTEntry, capacity)),
   137   _buckets(NEW_C_HEAP_ARRAY(int, capacity)),
   138   _free_list(NullEntry), _free_region(0)
   139 {
   140   clear();
   141 }
   143 RSHashTable::~RSHashTable() {
   144   if (_entries != NULL) {
   145     FREE_C_HEAP_ARRAY(SparsePRTEntry, _entries);
   146     _entries = NULL;
   147   }
   148   if (_buckets != NULL) {
   149     FREE_C_HEAP_ARRAY(int, _buckets);
   150     _buckets = NULL;
   151   }
   152 }
   154 void RSHashTable::clear() {
   155   _occupied_entries = 0;
   156   _occupied_cards = 0;
   157   guarantee(_entries != NULL, "INV");
   158   guarantee(_buckets != NULL, "INV");
   160   guarantee(_capacity <= ((size_t)1 << (sizeof(int)*BitsPerByte-1)) - 1,
   161                 "_capacity too large");
   163   // This will put -1 == NullEntry in the key field of all entries.
   164   memset(_entries, -1, _capacity * sizeof(SparsePRTEntry));
   165   memset(_buckets, -1, _capacity * sizeof(int));
   166   _free_list = NullEntry;
   167   _free_region = 0;
   168 }
   170 bool RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) {
   171   SparsePRTEntry* e = entry_for_region_ind_create(region_ind);
   172   assert(e != NULL && e->r_ind() == region_ind,
   173          "Postcondition of call above.");
   174   SparsePRTEntry::AddCardResult res = e->add_card(card_index);
   175   if (res == SparsePRTEntry::added) _occupied_cards++;
   176 #if SPARSE_PRT_VERBOSE
   177   gclog_or_tty->print_cr("       after add_card[%d]: valid-cards = %d.",
   178                 pointer_delta(e, _entries, sizeof(SparsePRTEntry)),
   179                 e->num_valid_cards());
   180 #endif
   181   assert(e->num_valid_cards() > 0, "Postcondition");
   182   return res != SparsePRTEntry::overflow;
   183 }
   185 bool RSHashTable::get_cards(RegionIdx_t region_ind, CardIdx_t* cards) {
   186   int ind = (int) (region_ind & capacity_mask());
   187   int cur_ind = _buckets[ind];
   188   SparsePRTEntry* cur;
   189   while (cur_ind != NullEntry &&
   190          (cur = entry(cur_ind))->r_ind() != region_ind) {
   191     cur_ind = cur->next_index();
   192   }
   194   if (cur_ind == NullEntry) return false;
   195   // Otherwise...
   196   assert(cur->r_ind() == region_ind, "Postcondition of loop + test above.");
   197   assert(cur->num_valid_cards() > 0, "Inv");
   198   cur->copy_cards(cards);
   199   return true;
   200 }
   202 bool RSHashTable::delete_entry(RegionIdx_t region_ind) {
   203   int ind = (int) (region_ind & capacity_mask());
   204   int* prev_loc = &_buckets[ind];
   205   int cur_ind = *prev_loc;
   206   SparsePRTEntry* cur;
   207   while (cur_ind != NullEntry &&
   208          (cur = entry(cur_ind))->r_ind() != region_ind) {
   209     prev_loc = cur->next_index_addr();
   210     cur_ind = *prev_loc;
   211   }
   213   if (cur_ind == NullEntry) return false;
   214   // Otherwise, splice out "cur".
   215   *prev_loc = cur->next_index();
   216   _occupied_cards -= cur->num_valid_cards();
   217   free_entry(cur_ind);
   218   _occupied_entries--;
   219   return true;
   220 }
   222 SparsePRTEntry*
   223 RSHashTable::entry_for_region_ind(RegionIdx_t region_ind) const {
   224   assert(occupied_entries() < capacity(), "Precondition");
   225   int ind = (int) (region_ind & capacity_mask());
   226   int cur_ind = _buckets[ind];
   227   SparsePRTEntry* cur;
   228   // XXX
   229   // int k = 0;
   230   while (cur_ind != NullEntry &&
   231          (cur = entry(cur_ind))->r_ind() != region_ind) {
   232     /*
   233     k++;
   234     if (k > 10) {
   235       gclog_or_tty->print_cr("RSHashTable::entry_for_region_ind(%d): "
   236                     "k = %d, cur_ind = %d.", region_ind, k, cur_ind);
   237       if (k >= 1000) {
   238         while (1) ;
   239       }
   240     }
   241     */
   242     cur_ind = cur->next_index();
   243   }
   245   if (cur_ind != NullEntry) {
   246     assert(cur->r_ind() == region_ind, "Loop postcondition + test");
   247     return cur;
   248   } else {
   249     return NULL;
   250   }
   251 }
   253 SparsePRTEntry*
   254 RSHashTable::entry_for_region_ind_create(RegionIdx_t region_ind) {
   255   SparsePRTEntry* res = entry_for_region_ind(region_ind);
   256   if (res == NULL) {
   257     int new_ind = alloc_entry();
   258     assert(0 <= new_ind && (size_t)new_ind < capacity(), "There should be room.");
   259     res = entry(new_ind);
   260     res->init(region_ind);
   261     // Insert at front.
   262     int ind = (int) (region_ind & capacity_mask());
   263     res->set_next_index(_buckets[ind]);
   264     _buckets[ind] = new_ind;
   265     _occupied_entries++;
   266   }
   267   return res;
   268 }
   270 int RSHashTable::alloc_entry() {
   271   int res;
   272   if (_free_list != NullEntry) {
   273     res = _free_list;
   274     _free_list = entry(res)->next_index();
   275     return res;
   276   } else if ((size_t) _free_region+1 < capacity()) {
   277     res = _free_region;
   278     _free_region++;
   279     return res;
   280   } else {
   281     return NullEntry;
   282   }
   283 }
   285 void RSHashTable::free_entry(int fi) {
   286   entry(fi)->set_next_index(_free_list);
   287   _free_list = fi;
   288 }
   290 void RSHashTable::add_entry(SparsePRTEntry* e) {
   291   assert(e->num_valid_cards() > 0, "Precondition.");
   292   SparsePRTEntry* e2 = entry_for_region_ind_create(e->r_ind());
   293   e->copy_cards(e2);
   294   _occupied_cards += e2->num_valid_cards();
   295   assert(e2->num_valid_cards() > 0, "Postcondition.");
   296 }
   298 CardIdx_t /* RSHashTable:: */ RSHashTableIter::find_first_card_in_list() {
   299   CardIdx_t res;
   300   while (_bl_ind != RSHashTable::NullEntry) {
   301     res = _rsht->entry(_bl_ind)->card(0);
   302     if (res != SparsePRTEntry::NullEntry) {
   303       return res;
   304     } else {
   305       _bl_ind = _rsht->entry(_bl_ind)->next_index();
   306     }
   307   }
   308   // Otherwise, none found:
   309   return SparsePRTEntry::NullEntry;
   310 }
   312 size_t /* RSHashTable:: */ RSHashTableIter::compute_card_ind(CardIdx_t ci) {
   313   return
   314     _heap_bot_card_ind
   315     + (_rsht->entry(_bl_ind)->r_ind() * HeapRegion::CardsPerRegion)
   316     + ci;
   317 }
   319 bool /* RSHashTable:: */ RSHashTableIter::has_next(size_t& card_index) {
   320   _card_ind++;
   321   CardIdx_t ci;
   322   if (_card_ind < SparsePRTEntry::CardsPerEntry &&
   323       ((ci = _rsht->entry(_bl_ind)->card(_card_ind)) !=
   324        SparsePRTEntry::NullEntry)) {
   325     card_index = compute_card_ind(ci);
   326     return true;
   327   }
   328   // Otherwise, must find the next valid entry.
   329   _card_ind = 0;
   331   if (_bl_ind != RSHashTable::NullEntry) {
   332       _bl_ind = _rsht->entry(_bl_ind)->next_index();
   333       ci = find_first_card_in_list();
   334       if (ci != SparsePRTEntry::NullEntry) {
   335         card_index = compute_card_ind(ci);
   336         return true;
   337       }
   338   }
   339   // If we didn't return above, must go to the next non-null table index.
   340   _tbl_ind++;
   341   while ((size_t)_tbl_ind < _rsht->capacity()) {
   342     _bl_ind = _rsht->_buckets[_tbl_ind];
   343     ci = find_first_card_in_list();
   344     if (ci != SparsePRTEntry::NullEntry) {
   345       card_index = compute_card_ind(ci);
   346       return true;
   347     }
   348     // Otherwise, try next entry.
   349     _tbl_ind++;
   350   }
   351   // Otherwise, there were no entry.
   352   return false;
   353 }
   355 bool RSHashTable::contains_card(RegionIdx_t region_index, CardIdx_t card_index) const {
   356   SparsePRTEntry* e = entry_for_region_ind(region_index);
   357   return (e != NULL && e->contains_card(card_index));
   358 }
   360 size_t RSHashTable::mem_size() const {
   361   return sizeof(this) +
   362     capacity() * (sizeof(SparsePRTEntry) + sizeof(int));
   363 }
   365 // ----------------------------------------------------------------------
   367 SparsePRT* SparsePRT::_head_expanded_list = NULL;
   369 void SparsePRT::add_to_expanded_list(SparsePRT* sprt) {
   370   // We could expand multiple times in a pause -- only put on list once.
   371   if (sprt->expanded()) return;
   372   sprt->set_expanded(true);
   373   SparsePRT* hd = _head_expanded_list;
   374   while (true) {
   375     sprt->_next_expanded = hd;
   376     SparsePRT* res =
   377       (SparsePRT*)
   378       Atomic::cmpxchg_ptr(sprt, &_head_expanded_list, hd);
   379     if (res == hd) return;
   380     else hd = res;
   381   }
   382 }
   385 SparsePRT* SparsePRT::get_from_expanded_list() {
   386   SparsePRT* hd = _head_expanded_list;
   387   while (hd != NULL) {
   388     SparsePRT* next = hd->next_expanded();
   389     SparsePRT* res =
   390       (SparsePRT*)
   391       Atomic::cmpxchg_ptr(next, &_head_expanded_list, hd);
   392     if (res == hd) {
   393       hd->set_next_expanded(NULL);
   394       return hd;
   395     } else {
   396       hd = res;
   397     }
   398   }
   399   return NULL;
   400 }
   403 void SparsePRT::cleanup_all() {
   404   // First clean up all expanded tables so they agree on next and cur.
   405   SparsePRT* sprt = get_from_expanded_list();
   406   while (sprt != NULL) {
   407     sprt->cleanup();
   408     sprt = get_from_expanded_list();
   409   }
   410 }
   413 SparsePRT::SparsePRT(HeapRegion* hr) :
   414   _expanded(false), _next_expanded(NULL)
   415 {
   416   _cur = new RSHashTable(InitialCapacity);
   417   _next = _cur;
   418 }
   421 SparsePRT::~SparsePRT() {
   422   assert(_next != NULL && _cur != NULL, "Inv");
   423   if (_cur != _next) { delete _cur; }
   424   delete _next;
   425 }
   428 size_t SparsePRT::mem_size() const {
   429   // We ignore "_cur" here, because it either = _next, or else it is
   430   // on the deleted list.
   431   return sizeof(this) + _next->mem_size();
   432 }
   434 bool SparsePRT::add_card(RegionIdx_t region_id, CardIdx_t card_index) {
   435 #if SPARSE_PRT_VERBOSE
   436   gclog_or_tty->print_cr("  Adding card %d from region %d to region %d sparse.",
   437                 card_index, region_id, _hr->hrs_index());
   438 #endif
   439   if (_next->occupied_entries() * 2 > _next->capacity()) {
   440     expand();
   441   }
   442   return _next->add_card(region_id, card_index);
   443 }
   445 bool SparsePRT::get_cards(RegionIdx_t region_id, CardIdx_t* cards) {
   446   return _next->get_cards(region_id, cards);
   447 }
   449 bool SparsePRT::delete_entry(RegionIdx_t region_id) {
   450   return _next->delete_entry(region_id);
   451 }
   453 void SparsePRT::clear() {
   454   // If they differ, _next is bigger then cur, so next has no chance of
   455   // being the initial size.
   456   if (_next != _cur) {
   457     delete _next;
   458   }
   460   if (_cur->capacity() != InitialCapacity) {
   461     delete _cur;
   462     _cur = new RSHashTable(InitialCapacity);
   463   } else {
   464     _cur->clear();
   465   }
   466   _next = _cur;
   467 }
   469 void SparsePRT::cleanup() {
   470   // Make sure that the current and next tables agree.
   471   if (_cur != _next) {
   472     delete _cur;
   473   }
   474   _cur = _next;
   475   set_expanded(false);
   476 }
   478 void SparsePRT::expand() {
   479   RSHashTable* last = _next;
   480   _next = new RSHashTable(last->capacity() * 2);
   482 #if SPARSE_PRT_VERBOSE
   483   gclog_or_tty->print_cr("  Expanded sparse table for %d to %d.",
   484                 _hr->hrs_index(), _next->capacity());
   485 #endif
   486   for (size_t i = 0; i < last->capacity(); i++) {
   487     SparsePRTEntry* e = last->entry((int)i);
   488     if (e->valid_entry()) {
   489 #if SPARSE_PRT_VERBOSE
   490       gclog_or_tty->print_cr("    During expansion, transferred entry for %d.",
   491                     e->r_ind());
   492 #endif
   493       _next->add_entry(e);
   494     }
   495   }
   496   if (last != _cur) {
   497     delete last;
   498   }
   499   add_to_expanded_list(this);
   500 }

mercurial