Mercurial > hg > truffle
comparison src/share/vm/memory/metaspace.cpp @ 12979:1d1ea10fe09f
8015255: NPG: Don't waste fragment at the end of a VirtualSpaceNode before retiring it.
Summary: Chunk up the last piece of committed memory in a VSN when getting a new one.
Reviewed-by: stefank, jmasa
author | mgerdin |
---|---|
date | Tue, 15 Oct 2013 13:56:46 +0200 |
parents | 94c0343b1887 |
children | 91a88c8450f4 |
comparison
equal
deleted
inserted
replaced
12907:bf9e50c573ad | 12979:1d1ea10fe09f |
---|---|
73 ClassSpecializedChunk = 128, | 73 ClassSpecializedChunk = 128, |
74 SpecializedChunk = 128, | 74 SpecializedChunk = 128, |
75 ClassSmallChunk = 256, | 75 ClassSmallChunk = 256, |
76 SmallChunk = 512, | 76 SmallChunk = 512, |
77 ClassMediumChunk = 4 * K, | 77 ClassMediumChunk = 4 * K, |
78 MediumChunk = 8 * K, | 78 MediumChunk = 8 * K |
79 HumongousChunkGranularity = 8 | |
80 }; | 79 }; |
81 | 80 |
82 static ChunkIndex next_chunk_index(ChunkIndex i) { | 81 static ChunkIndex next_chunk_index(ChunkIndex i) { |
83 assert(i < NumberOfInUseLists, "Out of bound"); | 82 assert(i < NumberOfInUseLists, "Out of bound"); |
84 return (ChunkIndex) (i+1); | 83 return (ChunkIndex) (i+1); |
90 | 89 |
91 typedef class FreeList<Metachunk> ChunkList; | 90 typedef class FreeList<Metachunk> ChunkList; |
92 | 91 |
93 // Manages the global free lists of chunks. | 92 // Manages the global free lists of chunks. |
94 class ChunkManager : public CHeapObj<mtInternal> { | 93 class ChunkManager : public CHeapObj<mtInternal> { |
94 friend class TestVirtualSpaceNodeTest; | |
95 | 95 |
96 // Free list of chunks of different sizes. | 96 // Free list of chunks of different sizes. |
97 // SpecializedChunk | 97 // SpecializedChunk |
98 // SmallChunk | 98 // SmallChunk |
99 // MediumChunk | 99 // MediumChunk |
255 | 255 |
256 // The first Metachunk will be allocated at the bottom of the | 256 // The first Metachunk will be allocated at the bottom of the |
257 // VirtualSpace | 257 // VirtualSpace |
258 Metachunk* first_chunk() { return (Metachunk*) bottom(); } | 258 Metachunk* first_chunk() { return (Metachunk*) bottom(); } |
259 | 259 |
260 // Committed but unused space in the virtual space | |
261 size_t free_words_in_vs() const; | |
260 public: | 262 public: |
261 | 263 |
262 VirtualSpaceNode(size_t byte_size); | 264 VirtualSpaceNode(size_t byte_size); |
263 VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {} | 265 VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {} |
264 ~VirtualSpaceNode(); | 266 ~VirtualSpaceNode(); |
299 #endif | 301 #endif |
300 | 302 |
301 // used and capacity in this single entry in the list | 303 // used and capacity in this single entry in the list |
302 size_t used_words_in_vs() const; | 304 size_t used_words_in_vs() const; |
303 size_t capacity_words_in_vs() const; | 305 size_t capacity_words_in_vs() const; |
304 size_t free_words_in_vs() const; | |
305 | 306 |
306 bool initialize(); | 307 bool initialize(); |
307 | 308 |
308 // get space from the virtual space | 309 // get space from the virtual space |
309 Metachunk* take_from_committed(size_t chunk_word_size); | 310 Metachunk* take_from_committed(size_t chunk_word_size); |
316 bool expand_by(size_t min_words, size_t preferred_words); | 317 bool expand_by(size_t min_words, size_t preferred_words); |
317 | 318 |
318 // In preparation for deleting this node, remove all the chunks | 319 // In preparation for deleting this node, remove all the chunks |
319 // in the node from any freelist. | 320 // in the node from any freelist. |
320 void purge(ChunkManager* chunk_manager); | 321 void purge(ChunkManager* chunk_manager); |
322 | |
323 // If an allocation doesn't fit in the current node a new node is created. | |
324 // Allocate chunks out of the remaining committed space in this node | |
325 // to avoid wasting that memory. | |
326 // This always adds up because all the chunk sizes are multiples of | |
327 // the smallest chunk size. | |
328 void retire(ChunkManager* chunk_manager); | |
321 | 329 |
322 #ifdef ASSERT | 330 #ifdef ASSERT |
323 // Debug support | 331 // Debug support |
324 void mangle(); | 332 void mangle(); |
325 #endif | 333 #endif |
459 // Get another virtual space and add it to the list. This | 467 // Get another virtual space and add it to the list. This |
460 // is typically prompted by a failed attempt to allocate a chunk | 468 // is typically prompted by a failed attempt to allocate a chunk |
461 // and is typically followed by the allocation of a chunk. | 469 // and is typically followed by the allocation of a chunk. |
462 bool create_new_virtual_space(size_t vs_word_size); | 470 bool create_new_virtual_space(size_t vs_word_size); |
463 | 471 |
472 // Chunk up the unused committed space in the current | |
473 // virtual space and add the chunks to the free list. | |
474 void retire_current_virtual_space(); | |
475 | |
464 public: | 476 public: |
465 VirtualSpaceList(size_t word_size); | 477 VirtualSpaceList(size_t word_size); |
466 VirtualSpaceList(ReservedSpace rs); | 478 VirtualSpaceList(ReservedSpace rs); |
467 | 479 |
468 size_t free_bytes(); | 480 size_t free_bytes(); |
622 }; | 634 }; |
623 | 635 |
624 bool is_class() { return _mdtype == Metaspace::ClassType; } | 636 bool is_class() { return _mdtype == Metaspace::ClassType; } |
625 | 637 |
626 // Accessors | 638 // Accessors |
627 size_t specialized_chunk_size() { return SpecializedChunk; } | 639 size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } |
628 size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } | 640 size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } |
629 size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } | 641 size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } |
630 size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } | 642 size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } |
643 | |
644 size_t smallest_chunk_size() { return specialized_chunk_size(); } | |
631 | 645 |
632 size_t allocated_blocks_words() const { return _allocated_blocks_words; } | 646 size_t allocated_blocks_words() const { return _allocated_blocks_words; } |
633 size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } | 647 size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } |
634 size_t allocated_chunks_words() const { return _allocated_chunks_words; } | 648 size_t allocated_chunks_words() const { return _allocated_chunks_words; } |
635 size_t allocated_chunks_count() const { return _allocated_chunks_count; } | 649 size_t allocated_chunks_count() const { return _allocated_chunks_count; } |
1054 } | 1068 } |
1055 } | 1069 } |
1056 #endif | 1070 #endif |
1057 } | 1071 } |
1058 | 1072 |
1073 void VirtualSpaceList::retire_current_virtual_space() { | |
1074 assert_lock_strong(SpaceManager::expand_lock()); | |
1075 | |
1076 VirtualSpaceNode* vsn = current_virtual_space(); | |
1077 | |
1078 ChunkManager* cm = is_class() ? Metaspace::chunk_manager_class() : | |
1079 Metaspace::chunk_manager_metadata(); | |
1080 | |
1081 vsn->retire(cm); | |
1082 } | |
1083 | |
1084 void VirtualSpaceNode::retire(ChunkManager* chunk_manager) { | |
1085 for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) { | |
1086 ChunkIndex index = (ChunkIndex)i; | |
1087 size_t chunk_size = chunk_manager->free_chunks(index)->size(); | |
1088 | |
1089 while (free_words_in_vs() >= chunk_size) { | |
1090 DEBUG_ONLY(verify_container_count();) | |
1091 Metachunk* chunk = get_chunk_vs(chunk_size); | |
1092 assert(chunk != NULL, "allocation should have been successful"); | |
1093 | |
1094 chunk_manager->return_chunks(index, chunk); | |
1095 chunk_manager->inc_free_chunks_total(chunk_size); | |
1096 DEBUG_ONLY(verify_container_count();) | |
1097 } | |
1098 } | |
1099 assert(free_words_in_vs() == 0, "should be empty now"); | |
1100 } | |
1101 | |
1059 VirtualSpaceList::VirtualSpaceList(size_t word_size) : | 1102 VirtualSpaceList::VirtualSpaceList(size_t word_size) : |
1060 _is_class(false), | 1103 _is_class(false), |
1061 _virtual_space_list(NULL), | 1104 _virtual_space_list(NULL), |
1062 _current_virtual_space(NULL), | 1105 _current_virtual_space(NULL), |
1063 _reserved_words(0), | 1106 _reserved_words(0), |
1179 min_words, | 1222 min_words, |
1180 max_expansion_words); | 1223 max_expansion_words); |
1181 if (vs_expanded) { | 1224 if (vs_expanded) { |
1182 return true; | 1225 return true; |
1183 } | 1226 } |
1227 retire_current_virtual_space(); | |
1184 | 1228 |
1185 // Get another virtual space. | 1229 // Get another virtual space. |
1186 size_t grow_vs_words = MAX2((size_t)VirtualSpaceSize, preferred_words); | 1230 size_t grow_vs_words = MAX2((size_t)VirtualSpaceSize, preferred_words); |
1187 grow_vs_words = align_size_up(grow_vs_words, Metaspace::reserve_alignment_words()); | 1231 grow_vs_words = align_size_up(grow_vs_words, Metaspace::reserve_alignment_words()); |
1188 | 1232 |
1900 } | 1944 } |
1901 } else { | 1945 } else { |
1902 chunk_word_size = medium_chunk_size(); | 1946 chunk_word_size = medium_chunk_size(); |
1903 } | 1947 } |
1904 | 1948 |
1905 // Might still need a humongous chunk. Enforce an | 1949 // Might still need a humongous chunk. Enforce |
1906 // eight word granularity to facilitate reuse (some | 1950 // humongous allocations sizes to be aligned up to |
1907 // wastage but better chance of reuse). | 1951 // the smallest chunk size. |
1908 size_t if_humongous_sized_chunk = | 1952 size_t if_humongous_sized_chunk = |
1909 align_size_up(word_size + Metachunk::overhead(), | 1953 align_size_up(word_size + Metachunk::overhead(), |
1910 HumongousChunkGranularity); | 1954 smallest_chunk_size()); |
1911 chunk_word_size = | 1955 chunk_word_size = |
1912 MAX2((size_t) chunk_word_size, if_humongous_sized_chunk); | 1956 MAX2((size_t) chunk_word_size, if_humongous_sized_chunk); |
1913 | 1957 |
1914 assert(!SpaceManager::is_humongous(word_size) || | 1958 assert(!SpaceManager::is_humongous(word_size) || |
1915 chunk_word_size == if_humongous_sized_chunk, | 1959 chunk_word_size == if_humongous_sized_chunk, |
2149 humongous_chunks, | 2193 humongous_chunks, |
2150 humongous_chunks->word_size()); | 2194 humongous_chunks->word_size()); |
2151 } | 2195 } |
2152 assert(humongous_chunks->word_size() == (size_t) | 2196 assert(humongous_chunks->word_size() == (size_t) |
2153 align_size_up(humongous_chunks->word_size(), | 2197 align_size_up(humongous_chunks->word_size(), |
2154 HumongousChunkGranularity), | 2198 smallest_chunk_size()), |
2155 err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT | 2199 err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT |
2156 " granularity %d", | 2200 " granularity %d", |
2157 humongous_chunks->word_size(), HumongousChunkGranularity)); | 2201 humongous_chunks->word_size(), smallest_chunk_size())); |
2158 Metachunk* next_humongous_chunks = humongous_chunks->next(); | 2202 Metachunk* next_humongous_chunks = humongous_chunks->next(); |
2159 humongous_chunks->container()->dec_container_count(); | 2203 humongous_chunks->container()->dec_container_count(); |
2160 chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); | 2204 chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); |
2161 humongous_chunks = next_humongous_chunks; | 2205 humongous_chunks = next_humongous_chunks; |
2162 } | 2206 } |
3492 | 3536 |
3493 void TestMetaspaceAux_test() { | 3537 void TestMetaspaceAux_test() { |
3494 TestMetaspaceAuxTest::test(); | 3538 TestMetaspaceAuxTest::test(); |
3495 } | 3539 } |
3496 | 3540 |
3541 class TestVirtualSpaceNodeTest { | |
3542 static void chunk_up(size_t words_left, size_t& num_medium_chunks, | |
3543 size_t& num_small_chunks, | |
3544 size_t& num_specialized_chunks) { | |
3545 num_medium_chunks = words_left / MediumChunk; | |
3546 words_left = words_left % MediumChunk; | |
3547 | |
3548 num_small_chunks = words_left / SmallChunk; | |
3549 words_left = words_left % SmallChunk; | |
3550 // how many specialized chunks can we get? | |
3551 num_specialized_chunks = words_left / SpecializedChunk; | |
3552 assert(words_left % SpecializedChunk == 0, "should be nothing left"); | |
3553 } | |
3554 | |
3555 public: | |
3556 static void test() { | |
3557 MutexLockerEx ml(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); | |
3558 const size_t vsn_test_size_words = MediumChunk * 4; | |
3559 const size_t vsn_test_size_bytes = vsn_test_size_words * BytesPerWord; | |
3560 | |
3561 // The chunk sizes must be multiples of eachother, or this will fail | |
3562 STATIC_ASSERT(MediumChunk % SmallChunk == 0); | |
3563 STATIC_ASSERT(SmallChunk % SpecializedChunk == 0); | |
3564 | |
3565 { // No committed memory in VSN | |
3566 ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); | |
3567 VirtualSpaceNode vsn(vsn_test_size_bytes); | |
3568 vsn.initialize(); | |
3569 vsn.retire(&cm); | |
3570 assert(cm.sum_free_chunks_count() == 0, "did not commit any memory in the VSN"); | |
3571 } | |
3572 | |
3573 { // All of VSN is committed, half is used by chunks | |
3574 ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); | |
3575 VirtualSpaceNode vsn(vsn_test_size_bytes); | |
3576 vsn.initialize(); | |
3577 vsn.expand_by(vsn_test_size_words, vsn_test_size_words); | |
3578 vsn.get_chunk_vs(MediumChunk); | |
3579 vsn.get_chunk_vs(MediumChunk); | |
3580 vsn.retire(&cm); | |
3581 assert(cm.sum_free_chunks_count() == 2, "should have been memory left for 2 medium chunks"); | |
3582 assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up"); | |
3583 } | |
3584 | |
3585 { // 4 pages of VSN is committed, some is used by chunks | |
3586 ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); | |
3587 VirtualSpaceNode vsn(vsn_test_size_bytes); | |
3588 const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord; | |
3589 assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size"); | |
3590 vsn.initialize(); | |
3591 vsn.expand_by(page_chunks, page_chunks); | |
3592 vsn.get_chunk_vs(SmallChunk); | |
3593 vsn.get_chunk_vs(SpecializedChunk); | |
3594 vsn.retire(&cm); | |
3595 | |
3596 // committed - used = words left to retire | |
3597 const size_t words_left = page_chunks - SmallChunk - SpecializedChunk; | |
3598 | |
3599 size_t num_medium_chunks, num_small_chunks, num_spec_chunks; | |
3600 chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks); | |
3601 | |
3602 assert(num_medium_chunks == 0, "should not get any medium chunks"); | |
3603 assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks"); | |
3604 assert(cm.sum_free_chunks() == words_left, "sizes should add up"); | |
3605 } | |
3606 | |
3607 { // Half of VSN is committed, a humongous chunk is used | |
3608 ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); | |
3609 VirtualSpaceNode vsn(vsn_test_size_bytes); | |
3610 vsn.initialize(); | |
3611 vsn.expand_by(MediumChunk * 2, MediumChunk * 2); | |
3612 vsn.get_chunk_vs(MediumChunk + SpecializedChunk); // Humongous chunks will be aligned up to MediumChunk + SpecializedChunk | |
3613 vsn.retire(&cm); | |
3614 | |
3615 const size_t words_left = MediumChunk * 2 - (MediumChunk + SpecializedChunk); | |
3616 size_t num_medium_chunks, num_small_chunks, num_spec_chunks; | |
3617 chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks); | |
3618 | |
3619 assert(num_medium_chunks == 0, "should not get any medium chunks"); | |
3620 assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks"); | |
3621 assert(cm.sum_free_chunks() == words_left, "sizes should add up"); | |
3622 } | |
3623 | |
3624 } | |
3625 }; | |
3626 | |
3627 void TestVirtualSpaceNode_test() { | |
3628 TestVirtualSpaceNodeTest::test(); | |
3629 } | |
3630 | |
3497 #endif | 3631 #endif |