1.1 --- a/src/share/vm/memory/metaspace.cpp Thu Oct 17 06:29:58 2013 -0700 1.2 +++ b/src/share/vm/memory/metaspace.cpp Tue Oct 15 13:56:46 2013 +0200 1.3 @@ -75,8 +75,7 @@ 1.4 ClassSmallChunk = 256, 1.5 SmallChunk = 512, 1.6 ClassMediumChunk = 4 * K, 1.7 - MediumChunk = 8 * K, 1.8 - HumongousChunkGranularity = 8 1.9 + MediumChunk = 8 * K 1.10 }; 1.11 1.12 static ChunkIndex next_chunk_index(ChunkIndex i) { 1.13 @@ -92,6 +91,7 @@ 1.14 1.15 // Manages the global free lists of chunks. 1.16 class ChunkManager : public CHeapObj<mtInternal> { 1.17 + friend class TestVirtualSpaceNodeTest; 1.18 1.19 // Free list of chunks of different sizes. 1.20 // SpecializedChunk 1.21 @@ -257,6 +257,8 @@ 1.22 // VirtualSpace 1.23 Metachunk* first_chunk() { return (Metachunk*) bottom(); } 1.24 1.25 + // Committed but unused space in the virtual space 1.26 + size_t free_words_in_vs() const; 1.27 public: 1.28 1.29 VirtualSpaceNode(size_t byte_size); 1.30 @@ -301,7 +303,6 @@ 1.31 // used and capacity in this single entry in the list 1.32 size_t used_words_in_vs() const; 1.33 size_t capacity_words_in_vs() const; 1.34 - size_t free_words_in_vs() const; 1.35 1.36 bool initialize(); 1.37 1.38 @@ -319,6 +320,13 @@ 1.39 // in the node from any freelist. 1.40 void purge(ChunkManager* chunk_manager); 1.41 1.42 + // If an allocation doesn't fit in the current node a new node is created. 1.43 + // Allocate chunks out of the remaining committed space in this node 1.44 + // to avoid wasting that memory. 1.45 + // This always adds up because all the chunk sizes are multiples of 1.46 + // the smallest chunk size. 1.47 + void retire(ChunkManager* chunk_manager); 1.48 + 1.49 #ifdef ASSERT 1.50 // Debug support 1.51 void mangle(); 1.52 @@ -461,6 +469,10 @@ 1.53 // and is typically followed by the allocation of a chunk. 1.54 bool create_new_virtual_space(size_t vs_word_size); 1.55 1.56 + // Chunk up the unused committed space in the current 1.57 + // virtual space and add the chunks to the free list. 1.58 + void retire_current_virtual_space(); 1.59 + 1.60 public: 1.61 VirtualSpaceList(size_t word_size); 1.62 VirtualSpaceList(ReservedSpace rs); 1.63 @@ -624,10 +636,12 @@ 1.64 bool is_class() { return _mdtype == Metaspace::ClassType; } 1.65 1.66 // Accessors 1.67 - size_t specialized_chunk_size() { return SpecializedChunk; } 1.68 - size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } 1.69 - size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } 1.70 - size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } 1.71 + size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } 1.72 + size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } 1.73 + size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } 1.74 + size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } 1.75 + 1.76 + size_t smallest_chunk_size() { return specialized_chunk_size(); } 1.77 1.78 size_t allocated_blocks_words() const { return _allocated_blocks_words; } 1.79 size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } 1.80 @@ -1056,6 +1070,35 @@ 1.81 #endif 1.82 } 1.83 1.84 +void VirtualSpaceList::retire_current_virtual_space() { 1.85 + assert_lock_strong(SpaceManager::expand_lock()); 1.86 + 1.87 + VirtualSpaceNode* vsn = current_virtual_space(); 1.88 + 1.89 + ChunkManager* cm = is_class() ? Metaspace::chunk_manager_class() : 1.90 + Metaspace::chunk_manager_metadata(); 1.91 + 1.92 + vsn->retire(cm); 1.93 +} 1.94 + 1.95 +void VirtualSpaceNode::retire(ChunkManager* chunk_manager) { 1.96 + for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) { 1.97 + ChunkIndex index = (ChunkIndex)i; 1.98 + size_t chunk_size = chunk_manager->free_chunks(index)->size(); 1.99 + 1.100 + while (free_words_in_vs() >= chunk_size) { 1.101 + DEBUG_ONLY(verify_container_count();) 1.102 + Metachunk* chunk = get_chunk_vs(chunk_size); 1.103 + assert(chunk != NULL, "allocation should have been successful"); 1.104 + 1.105 + chunk_manager->return_chunks(index, chunk); 1.106 + chunk_manager->inc_free_chunks_total(chunk_size); 1.107 + DEBUG_ONLY(verify_container_count();) 1.108 + } 1.109 + } 1.110 + assert(free_words_in_vs() == 0, "should be empty now"); 1.111 +} 1.112 + 1.113 VirtualSpaceList::VirtualSpaceList(size_t word_size) : 1.114 _is_class(false), 1.115 _virtual_space_list(NULL), 1.116 @@ -1181,6 +1224,7 @@ 1.117 if (vs_expanded) { 1.118 return true; 1.119 } 1.120 + retire_current_virtual_space(); 1.121 1.122 // Get another virtual space. 1.123 size_t grow_vs_words = MAX2((size_t)VirtualSpaceSize, preferred_words); 1.124 @@ -1902,12 +1946,12 @@ 1.125 chunk_word_size = medium_chunk_size(); 1.126 } 1.127 1.128 - // Might still need a humongous chunk. Enforce an 1.129 - // eight word granularity to facilitate reuse (some 1.130 - // wastage but better chance of reuse). 1.131 + // Might still need a humongous chunk. Enforce 1.132 + // humongous allocations sizes to be aligned up to 1.133 + // the smallest chunk size. 1.134 size_t if_humongous_sized_chunk = 1.135 align_size_up(word_size + Metachunk::overhead(), 1.136 - HumongousChunkGranularity); 1.137 + smallest_chunk_size()); 1.138 chunk_word_size = 1.139 MAX2((size_t) chunk_word_size, if_humongous_sized_chunk); 1.140 1.141 @@ -2151,10 +2195,10 @@ 1.142 } 1.143 assert(humongous_chunks->word_size() == (size_t) 1.144 align_size_up(humongous_chunks->word_size(), 1.145 - HumongousChunkGranularity), 1.146 + smallest_chunk_size()), 1.147 err_msg("Humongous chunk size is wrong: word size " SIZE_FORMAT 1.148 " granularity %d", 1.149 - humongous_chunks->word_size(), HumongousChunkGranularity)); 1.150 + humongous_chunks->word_size(), smallest_chunk_size())); 1.151 Metachunk* next_humongous_chunks = humongous_chunks->next(); 1.152 humongous_chunks->container()->dec_container_count(); 1.153 chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); 1.154 @@ -3494,4 +3538,94 @@ 1.155 TestMetaspaceAuxTest::test(); 1.156 } 1.157 1.158 +class TestVirtualSpaceNodeTest { 1.159 + static void chunk_up(size_t words_left, size_t& num_medium_chunks, 1.160 + size_t& num_small_chunks, 1.161 + size_t& num_specialized_chunks) { 1.162 + num_medium_chunks = words_left / MediumChunk; 1.163 + words_left = words_left % MediumChunk; 1.164 + 1.165 + num_small_chunks = words_left / SmallChunk; 1.166 + words_left = words_left % SmallChunk; 1.167 + // how many specialized chunks can we get? 1.168 + num_specialized_chunks = words_left / SpecializedChunk; 1.169 + assert(words_left % SpecializedChunk == 0, "should be nothing left"); 1.170 + } 1.171 + 1.172 + public: 1.173 + static void test() { 1.174 + MutexLockerEx ml(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); 1.175 + const size_t vsn_test_size_words = MediumChunk * 4; 1.176 + const size_t vsn_test_size_bytes = vsn_test_size_words * BytesPerWord; 1.177 + 1.178 + // The chunk sizes must be multiples of eachother, or this will fail 1.179 + STATIC_ASSERT(MediumChunk % SmallChunk == 0); 1.180 + STATIC_ASSERT(SmallChunk % SpecializedChunk == 0); 1.181 + 1.182 + { // No committed memory in VSN 1.183 + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); 1.184 + VirtualSpaceNode vsn(vsn_test_size_bytes); 1.185 + vsn.initialize(); 1.186 + vsn.retire(&cm); 1.187 + assert(cm.sum_free_chunks_count() == 0, "did not commit any memory in the VSN"); 1.188 + } 1.189 + 1.190 + { // All of VSN is committed, half is used by chunks 1.191 + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); 1.192 + VirtualSpaceNode vsn(vsn_test_size_bytes); 1.193 + vsn.initialize(); 1.194 + vsn.expand_by(vsn_test_size_words, vsn_test_size_words); 1.195 + vsn.get_chunk_vs(MediumChunk); 1.196 + vsn.get_chunk_vs(MediumChunk); 1.197 + vsn.retire(&cm); 1.198 + assert(cm.sum_free_chunks_count() == 2, "should have been memory left for 2 medium chunks"); 1.199 + assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up"); 1.200 + } 1.201 + 1.202 + { // 4 pages of VSN is committed, some is used by chunks 1.203 + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); 1.204 + VirtualSpaceNode vsn(vsn_test_size_bytes); 1.205 + const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord; 1.206 + assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size"); 1.207 + vsn.initialize(); 1.208 + vsn.expand_by(page_chunks, page_chunks); 1.209 + vsn.get_chunk_vs(SmallChunk); 1.210 + vsn.get_chunk_vs(SpecializedChunk); 1.211 + vsn.retire(&cm); 1.212 + 1.213 + // committed - used = words left to retire 1.214 + const size_t words_left = page_chunks - SmallChunk - SpecializedChunk; 1.215 + 1.216 + size_t num_medium_chunks, num_small_chunks, num_spec_chunks; 1.217 + chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks); 1.218 + 1.219 + assert(num_medium_chunks == 0, "should not get any medium chunks"); 1.220 + assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks"); 1.221 + assert(cm.sum_free_chunks() == words_left, "sizes should add up"); 1.222 + } 1.223 + 1.224 + { // Half of VSN is committed, a humongous chunk is used 1.225 + ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk); 1.226 + VirtualSpaceNode vsn(vsn_test_size_bytes); 1.227 + vsn.initialize(); 1.228 + vsn.expand_by(MediumChunk * 2, MediumChunk * 2); 1.229 + vsn.get_chunk_vs(MediumChunk + SpecializedChunk); // Humongous chunks will be aligned up to MediumChunk + SpecializedChunk 1.230 + vsn.retire(&cm); 1.231 + 1.232 + const size_t words_left = MediumChunk * 2 - (MediumChunk + SpecializedChunk); 1.233 + size_t num_medium_chunks, num_small_chunks, num_spec_chunks; 1.234 + chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks); 1.235 + 1.236 + assert(num_medium_chunks == 0, "should not get any medium chunks"); 1.237 + assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks"); 1.238 + assert(cm.sum_free_chunks() == words_left, "sizes should add up"); 1.239 + } 1.240 + 1.241 + } 1.242 +}; 1.243 + 1.244 +void TestVirtualSpaceNode_test() { 1.245 + TestVirtualSpaceNodeTest::test(); 1.246 +} 1.247 + 1.248 #endif