Mercurial > hg > graal-compiler
comparison src/share/vm/memory/metaspace.cpp @ 10101:df254344edf1
8011173: NPG: Replace the ChunkList implementation with class FreeList<Metachunk>
Reviewed-by: mgerdin, tschatzl, johnc, coleenp
author | jmasa |
---|---|
date | Mon, 01 Apr 2013 10:50:30 -0700 |
parents | 6574f999e0cf |
children | c23dbf0e8ab7 |
comparison
equal
deleted
inserted
replaced
10100:9aa8d8037ee3 | 10101:df254344edf1 |
---|---|
101 // list of the chunks it is using and the current chunk. The current | 101 // list of the chunks it is using and the current chunk. The current |
102 // chunk is the chunk from which allocations are done. Space freed in | 102 // chunk is the chunk from which allocations are done. Space freed in |
103 // a chunk is placed on the free list of blocks (BlockFreelist) and | 103 // a chunk is placed on the free list of blocks (BlockFreelist) and |
104 // reused from there. | 104 // reused from there. |
105 | 105 |
106 // Pointer to list of Metachunks. | 106 typedef class FreeList<Metachunk> ChunkList; |
107 class ChunkList VALUE_OBJ_CLASS_SPEC { | |
108 // List of free chunks | |
109 Metachunk* _head; | |
110 | |
111 public: | |
112 // Constructor | |
113 ChunkList() : _head(NULL) {} | |
114 | |
115 // Accessors | |
116 Metachunk* head() { return _head; } | |
117 void set_head(Metachunk* v) { _head = v; } | |
118 | |
119 // Link at head of the list | |
120 void add_at_head(Metachunk* head, Metachunk* tail); | |
121 void add_at_head(Metachunk* head); | |
122 | |
123 size_t sum_list_size(); | |
124 size_t sum_list_count(); | |
125 size_t sum_list_capacity(); | |
126 }; | |
127 | 107 |
128 // Manages the global free lists of chunks. | 108 // Manages the global free lists of chunks. |
129 // Has three lists of free chunks, and a total size and | 109 // Has three lists of free chunks, and a total size and |
130 // count that includes all three | 110 // count that includes all three |
131 | 111 |
182 void chunk_freelist_deallocate(Metachunk* chunk); | 162 void chunk_freelist_deallocate(Metachunk* chunk); |
183 | 163 |
184 // Map a size to a list index assuming that there are lists | 164 // Map a size to a list index assuming that there are lists |
185 // for special, small, medium, and humongous chunks. | 165 // for special, small, medium, and humongous chunks. |
186 static ChunkIndex list_index(size_t size); | 166 static ChunkIndex list_index(size_t size); |
167 | |
168 // Add the simple linked list of chunks to the freelist of chunks | |
169 // of type index. | |
170 void return_chunks(ChunkIndex index, Metachunk* chunks); | |
187 | 171 |
188 // Total of the space in the free chunks list | 172 // Total of the space in the free chunks list |
189 size_t free_chunks_total(); | 173 size_t free_chunks_total(); |
190 size_t free_chunks_total_in_bytes(); | 174 size_t free_chunks_total_in_bytes(); |
191 | 175 |
897 _virtual_space_count(0) { | 881 _virtual_space_count(0) { |
898 MutexLockerEx cl(SpaceManager::expand_lock(), | 882 MutexLockerEx cl(SpaceManager::expand_lock(), |
899 Mutex::_no_safepoint_check_flag); | 883 Mutex::_no_safepoint_check_flag); |
900 bool initialization_succeeded = grow_vs(word_size); | 884 bool initialization_succeeded = grow_vs(word_size); |
901 | 885 |
886 _chunk_manager.free_chunks(SpecializedIndex)->set_size(SpecializedChunk); | |
887 _chunk_manager.free_chunks(SmallIndex)->set_size(SmallChunk); | |
888 _chunk_manager.free_chunks(MediumIndex)->set_size(MediumChunk); | |
902 assert(initialization_succeeded, | 889 assert(initialization_succeeded, |
903 " VirtualSpaceList initialization should not fail"); | 890 " VirtualSpaceList initialization should not fail"); |
904 } | 891 } |
905 | 892 |
906 VirtualSpaceList::VirtualSpaceList(ReservedSpace rs) : | 893 VirtualSpaceList::VirtualSpaceList(ReservedSpace rs) : |
911 _virtual_space_count(0) { | 898 _virtual_space_count(0) { |
912 MutexLockerEx cl(SpaceManager::expand_lock(), | 899 MutexLockerEx cl(SpaceManager::expand_lock(), |
913 Mutex::_no_safepoint_check_flag); | 900 Mutex::_no_safepoint_check_flag); |
914 VirtualSpaceNode* class_entry = new VirtualSpaceNode(rs); | 901 VirtualSpaceNode* class_entry = new VirtualSpaceNode(rs); |
915 bool succeeded = class_entry->initialize(); | 902 bool succeeded = class_entry->initialize(); |
903 _chunk_manager.free_chunks(SpecializedIndex)->set_size(SpecializedChunk); | |
904 _chunk_manager.free_chunks(SmallIndex)->set_size(ClassSmallChunk); | |
905 _chunk_manager.free_chunks(MediumIndex)->set_size(ClassMediumChunk); | |
916 assert(succeeded, " VirtualSpaceList initialization should not fail"); | 906 assert(succeeded, " VirtualSpaceList initialization should not fail"); |
917 link_vs(class_entry, rs.size()/BytesPerWord); | 907 link_vs(class_entry, rs.size()/BytesPerWord); |
918 } | 908 } |
919 | 909 |
920 // Allocate another meta virtual space and add it to the list. | 910 // Allocate another meta virtual space and add it to the list. |
1378 } | 1368 } |
1379 return false; | 1369 return false; |
1380 } | 1370 } |
1381 #endif | 1371 #endif |
1382 | 1372 |
1383 // ChunkList methods | |
1384 | |
1385 size_t ChunkList::sum_list_size() { | |
1386 size_t result = 0; | |
1387 Metachunk* cur = head(); | |
1388 while (cur != NULL) { | |
1389 result += cur->word_size(); | |
1390 cur = cur->next(); | |
1391 } | |
1392 return result; | |
1393 } | |
1394 | |
1395 size_t ChunkList::sum_list_count() { | |
1396 size_t result = 0; | |
1397 Metachunk* cur = head(); | |
1398 while (cur != NULL) { | |
1399 result++; | |
1400 cur = cur->next(); | |
1401 } | |
1402 return result; | |
1403 } | |
1404 | |
1405 size_t ChunkList::sum_list_capacity() { | |
1406 size_t result = 0; | |
1407 Metachunk* cur = head(); | |
1408 while (cur != NULL) { | |
1409 result += cur->capacity_word_size(); | |
1410 cur = cur->next(); | |
1411 } | |
1412 return result; | |
1413 } | |
1414 | |
1415 void ChunkList::add_at_head(Metachunk* head, Metachunk* tail) { | |
1416 assert_lock_strong(SpaceManager::expand_lock()); | |
1417 assert(head == tail || tail->next() == NULL, | |
1418 "Not the tail or the head has already been added to a list"); | |
1419 | |
1420 if (TraceMetadataChunkAllocation && Verbose) { | |
1421 gclog_or_tty->print("ChunkList::add_at_head(head, tail): "); | |
1422 Metachunk* cur = head; | |
1423 while (cur != NULL) { | |
1424 gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ", cur, cur->word_size()); | |
1425 cur = cur->next(); | |
1426 } | |
1427 gclog_or_tty->print_cr(""); | |
1428 } | |
1429 | |
1430 if (tail != NULL) { | |
1431 tail->set_next(_head); | |
1432 } | |
1433 set_head(head); | |
1434 } | |
1435 | |
1436 void ChunkList::add_at_head(Metachunk* list) { | |
1437 if (list == NULL) { | |
1438 // Nothing to add | |
1439 return; | |
1440 } | |
1441 assert_lock_strong(SpaceManager::expand_lock()); | |
1442 Metachunk* head = list; | |
1443 Metachunk* tail = list; | |
1444 Metachunk* cur = head->next(); | |
1445 // Search for the tail since it is not passed. | |
1446 while (cur != NULL) { | |
1447 tail = cur; | |
1448 cur = cur->next(); | |
1449 } | |
1450 add_at_head(head, tail); | |
1451 } | |
1452 | |
1453 // ChunkManager methods | 1373 // ChunkManager methods |
1454 | 1374 |
1455 // Verification of _free_chunks_total and _free_chunks_count does not | 1375 // Verification of _free_chunks_total and _free_chunks_count does not |
1456 // work with the CMS collector because its use of additional locks | 1376 // work with the CMS collector because its use of additional locks |
1457 // complicate the mutex deadlock detection but it can still be useful | 1377 // complicate the mutex deadlock detection but it can still be useful |
1551 | 1471 |
1552 if (list == NULL) { | 1472 if (list == NULL) { |
1553 continue; | 1473 continue; |
1554 } | 1474 } |
1555 | 1475 |
1556 result = result + list->sum_list_capacity(); | 1476 result = result + list->count() * list->size(); |
1557 } | 1477 } |
1558 result = result + humongous_dictionary()->total_size(); | 1478 result = result + humongous_dictionary()->total_size(); |
1559 return result; | 1479 return result; |
1560 } | 1480 } |
1561 | 1481 |
1565 for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { | 1485 for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { |
1566 ChunkList* list = free_chunks(i); | 1486 ChunkList* list = free_chunks(i); |
1567 if (list == NULL) { | 1487 if (list == NULL) { |
1568 continue; | 1488 continue; |
1569 } | 1489 } |
1570 count = count + list->sum_list_count(); | 1490 count = count + list->count(); |
1571 } | 1491 } |
1572 count = count + humongous_dictionary()->total_free_blocks(); | 1492 count = count + humongous_dictionary()->total_free_blocks(); |
1573 return count; | 1493 return count; |
1574 } | 1494 } |
1575 | 1495 |
1620 if (chunk == NULL) { | 1540 if (chunk == NULL) { |
1621 return NULL; | 1541 return NULL; |
1622 } | 1542 } |
1623 | 1543 |
1624 // Remove the chunk as the head of the list. | 1544 // Remove the chunk as the head of the list. |
1625 free_list->set_head(chunk->next()); | 1545 free_list->remove_chunk(chunk); |
1626 | 1546 |
1627 // Chunk is being removed from the chunks free list. | 1547 // Chunk is being removed from the chunks free list. |
1628 dec_free_chunks_total(chunk->capacity_word_size()); | 1548 dec_free_chunks_total(chunk->capacity_word_size()); |
1629 | 1549 |
1630 if (TraceMetadataChunkAllocation && Verbose) { | 1550 if (TraceMetadataChunkAllocation && Verbose) { |
1677 "Non-humongous variable sized chunk"); | 1597 "Non-humongous variable sized chunk"); |
1678 if (TraceMetadataChunkAllocation) { | 1598 if (TraceMetadataChunkAllocation) { |
1679 size_t list_count; | 1599 size_t list_count; |
1680 if (list_index(word_size) < HumongousIndex) { | 1600 if (list_index(word_size) < HumongousIndex) { |
1681 ChunkList* list = find_free_chunks_list(word_size); | 1601 ChunkList* list = find_free_chunks_list(word_size); |
1682 list_count = list->sum_list_count(); | 1602 list_count = list->count(); |
1683 } else { | 1603 } else { |
1684 list_count = humongous_dictionary()->total_count(); | 1604 list_count = humongous_dictionary()->total_count(); |
1685 } | 1605 } |
1686 tty->print("ChunkManager::chunk_freelist_allocate: " PTR_FORMAT " chunk " | 1606 tty->print("ChunkManager::chunk_freelist_allocate: " PTR_FORMAT " chunk " |
1687 PTR_FORMAT " size " SIZE_FORMAT " count " SIZE_FORMAT " ", | 1607 PTR_FORMAT " size " SIZE_FORMAT " count " SIZE_FORMAT " ", |
1956 if (TraceMetadataChunkAllocation && Verbose) { | 1876 if (TraceMetadataChunkAllocation && Verbose) { |
1957 gclog_or_tty->print_cr("SpaceManager(): " PTR_FORMAT, this); | 1877 gclog_or_tty->print_cr("SpaceManager(): " PTR_FORMAT, this); |
1958 } | 1878 } |
1959 } | 1879 } |
1960 | 1880 |
1881 void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { | |
1882 if (chunks == NULL) { | |
1883 return; | |
1884 } | |
1885 ChunkList* list = free_chunks(index); | |
1886 assert(list->size() == chunks->word_size(), "Mismatch in chunk sizes"); | |
1887 assert_lock_strong(SpaceManager::expand_lock()); | |
1888 Metachunk* cur = chunks; | |
1889 | |
1890 // This return chunks one at a time. If a new | |
1891 // class List can be created that is a base class | |
1892 // of FreeList then something like FreeList::prepend() | |
1893 // can be used in place of this loop | |
1894 while (cur != NULL) { | |
1895 // Capture the next link before it is changed | |
1896 // by the call to return_chunk_at_head(); | |
1897 Metachunk* next = cur->next(); | |
1898 cur->set_is_free(true); | |
1899 list->return_chunk_at_head(cur); | |
1900 cur = next; | |
1901 } | |
1902 } | |
1903 | |
1961 SpaceManager::~SpaceManager() { | 1904 SpaceManager::~SpaceManager() { |
1962 // This call this->_lock which can't be done while holding expand_lock() | 1905 // This call this->_lock which can't be done while holding expand_lock() |
1963 const size_t in_use_before = sum_capacity_in_chunks_in_use(); | 1906 const size_t in_use_before = sum_capacity_in_chunks_in_use(); |
1964 | 1907 |
1965 MutexLockerEx fcl(SpaceManager::expand_lock(), | 1908 MutexLockerEx fcl(SpaceManager::expand_lock(), |
1993 gclog_or_tty->print_cr("returned %d %s chunks to freelist", | 1936 gclog_or_tty->print_cr("returned %d %s chunks to freelist", |
1994 sum_count_in_chunks_in_use(i), | 1937 sum_count_in_chunks_in_use(i), |
1995 chunk_size_name(i)); | 1938 chunk_size_name(i)); |
1996 } | 1939 } |
1997 Metachunk* chunks = chunks_in_use(i); | 1940 Metachunk* chunks = chunks_in_use(i); |
1998 chunk_manager->free_chunks(i)->add_at_head(chunks); | 1941 chunk_manager->return_chunks(i, chunks); |
1999 set_chunks_in_use(i, NULL); | 1942 set_chunks_in_use(i, NULL); |
2000 if (TraceMetadataChunkAllocation && Verbose) { | 1943 if (TraceMetadataChunkAllocation && Verbose) { |
2001 gclog_or_tty->print_cr("updated freelist count %d %s", | 1944 gclog_or_tty->print_cr("updated freelist count %d %s", |
2002 chunk_manager->free_chunks(i)->sum_list_count(), | 1945 chunk_manager->free_chunks(i)->count(), |
2003 chunk_size_name(i)); | 1946 chunk_size_name(i)); |
2004 } | 1947 } |
2005 assert(i != HumongousIndex, "Humongous chunks are handled explicitly later"); | 1948 assert(i != HumongousIndex, "Humongous chunks are handled explicitly later"); |
2006 } | 1949 } |
2007 | 1950 |