hotspot/src/share/vm/memory/metaspace.cpp
changeset 21189 e851a0a007ce
parent 21188 d053e4e8f901
parent 21113 65e0eb464169
child 21518 067dd7967128
child 21562 f3f6ea8474d0
equal deleted inserted replaced
21188:d053e4e8f901 21189:e851a0a007ce
    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   }
  3310           loader_data, word_size, mdtype);
  3354           loader_data, word_size, mdtype);
  3311     }
  3355     }
  3312   }
  3356   }
  3313 
  3357 
  3314   if (result == NULL) {
  3358   if (result == NULL) {
  3315     report_metadata_oome(loader_data, word_size, mdtype, THREAD);
  3359     report_metadata_oome(loader_data, word_size, mdtype, CHECK_NULL);
  3316     // Will not reach here.
       
  3317     return NULL;
       
  3318   }
  3360   }
  3319 
  3361 
  3320   // Zero initialize.
  3362   // Zero initialize.
  3321   Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
  3363   Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
  3322 
  3364 
  3518 
  3560 
  3519 void TestMetaspaceAux_test() {
  3561 void TestMetaspaceAux_test() {
  3520   TestMetaspaceAuxTest::test();
  3562   TestMetaspaceAuxTest::test();
  3521 }
  3563 }
  3522 
  3564 
       
  3565 class TestVirtualSpaceNodeTest {
       
  3566   static void chunk_up(size_t words_left, size_t& num_medium_chunks,
       
  3567                                           size_t& num_small_chunks,
       
  3568                                           size_t& num_specialized_chunks) {
       
  3569     num_medium_chunks = words_left / MediumChunk;
       
  3570     words_left = words_left % MediumChunk;
       
  3571 
       
  3572     num_small_chunks = words_left / SmallChunk;
       
  3573     words_left = words_left % SmallChunk;
       
  3574     // how many specialized chunks can we get?
       
  3575     num_specialized_chunks = words_left / SpecializedChunk;
       
  3576     assert(words_left % SpecializedChunk == 0, "should be nothing left");
       
  3577   }
       
  3578 
       
  3579  public:
       
  3580   static void test() {
       
  3581     MutexLockerEx ml(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
       
  3582     const size_t vsn_test_size_words = MediumChunk  * 4;
       
  3583     const size_t vsn_test_size_bytes = vsn_test_size_words * BytesPerWord;
       
  3584 
       
  3585     // The chunk sizes must be multiples of eachother, or this will fail
       
  3586     STATIC_ASSERT(MediumChunk % SmallChunk == 0);
       
  3587     STATIC_ASSERT(SmallChunk % SpecializedChunk == 0);
       
  3588 
       
  3589     { // No committed memory in VSN
       
  3590       ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
       
  3591       VirtualSpaceNode vsn(vsn_test_size_bytes);
       
  3592       vsn.initialize();
       
  3593       vsn.retire(&cm);
       
  3594       assert(cm.sum_free_chunks_count() == 0, "did not commit any memory in the VSN");
       
  3595     }
       
  3596 
       
  3597     { // All of VSN is committed, half is used by chunks
       
  3598       ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
       
  3599       VirtualSpaceNode vsn(vsn_test_size_bytes);
       
  3600       vsn.initialize();
       
  3601       vsn.expand_by(vsn_test_size_words, vsn_test_size_words);
       
  3602       vsn.get_chunk_vs(MediumChunk);
       
  3603       vsn.get_chunk_vs(MediumChunk);
       
  3604       vsn.retire(&cm);
       
  3605       assert(cm.sum_free_chunks_count() == 2, "should have been memory left for 2 medium chunks");
       
  3606       assert(cm.sum_free_chunks() == 2*MediumChunk, "sizes should add up");
       
  3607     }
       
  3608 
       
  3609     { // 4 pages of VSN is committed, some is used by chunks
       
  3610       ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
       
  3611       VirtualSpaceNode vsn(vsn_test_size_bytes);
       
  3612       const size_t page_chunks = 4 * (size_t)os::vm_page_size() / BytesPerWord;
       
  3613       assert(page_chunks < MediumChunk, "Test expects medium chunks to be at least 4*page_size");
       
  3614       vsn.initialize();
       
  3615       vsn.expand_by(page_chunks, page_chunks);
       
  3616       vsn.get_chunk_vs(SmallChunk);
       
  3617       vsn.get_chunk_vs(SpecializedChunk);
       
  3618       vsn.retire(&cm);
       
  3619 
       
  3620       // committed - used = words left to retire
       
  3621       const size_t words_left = page_chunks - SmallChunk - SpecializedChunk;
       
  3622 
       
  3623       size_t num_medium_chunks, num_small_chunks, num_spec_chunks;
       
  3624       chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks);
       
  3625 
       
  3626       assert(num_medium_chunks == 0, "should not get any medium chunks");
       
  3627       assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks");
       
  3628       assert(cm.sum_free_chunks() == words_left, "sizes should add up");
       
  3629     }
       
  3630 
       
  3631     { // Half of VSN is committed, a humongous chunk is used
       
  3632       ChunkManager cm(SpecializedChunk, SmallChunk, MediumChunk);
       
  3633       VirtualSpaceNode vsn(vsn_test_size_bytes);
       
  3634       vsn.initialize();
       
  3635       vsn.expand_by(MediumChunk * 2, MediumChunk * 2);
       
  3636       vsn.get_chunk_vs(MediumChunk + SpecializedChunk); // Humongous chunks will be aligned up to MediumChunk + SpecializedChunk
       
  3637       vsn.retire(&cm);
       
  3638 
       
  3639       const size_t words_left = MediumChunk * 2 - (MediumChunk + SpecializedChunk);
       
  3640       size_t num_medium_chunks, num_small_chunks, num_spec_chunks;
       
  3641       chunk_up(words_left, num_medium_chunks, num_small_chunks, num_spec_chunks);
       
  3642 
       
  3643       assert(num_medium_chunks == 0, "should not get any medium chunks");
       
  3644       assert(cm.sum_free_chunks_count() == (num_small_chunks + num_spec_chunks), "should be space for 3 chunks");
       
  3645       assert(cm.sum_free_chunks() == words_left, "sizes should add up");
       
  3646     }
       
  3647 
       
  3648   }
       
  3649 };
       
  3650 
       
  3651 void TestVirtualSpaceNode_test() {
       
  3652   TestVirtualSpaceNodeTest::test();
       
  3653 }
       
  3654 
  3523 #endif
  3655 #endif