--- old/src/share/vm/memory/metaspace.cpp 2015-05-27 10:08:24.166761034 -0400 +++ new/src/share/vm/memory/metaspace.cpp 2015-05-27 10:08:23.530724741 -0400 @@ -615,8 +615,7 @@ Metachunk* _chunks_in_use[NumberOfInUseLists]; Metachunk* _current_chunk; - // Number of small chunks to allocate to a manager - // If class space manager, small chunks are unlimited + // Maximum number of small chunks to allocate to a SpaceManager static uint const _small_chunk_limit; // Sum of all space in allocated chunks @@ -731,6 +730,8 @@ // Block allocation and deallocation. // Allocates a block from the current chunk MetaWord* allocate(size_t word_size); + // Allocates a block from a small chunk + MetaWord* get_small_chunk_and_allocate(size_t word_size); // Helper for allocations MetaWord* allocate_work(size_t word_size); @@ -2012,9 +2013,8 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) { // Decide between a small chunk and a medium chunk. Up to - // _small_chunk_limit small chunks can be allocated but - // once a medium chunk has been allocated, no more small - // chunks will be allocated. + // _small_chunk_limit small chunks can be allocated. + // After that a medium chunk is preferred. size_t chunk_word_size; if (chunks_in_use(MediumIndex) == NULL && sum_count_in_chunks_in_use(SmallIndex) < _small_chunk_limit) { @@ -2082,7 +2082,7 @@ word_size, words_used, words_left); } - // Get another chunk out of the virtual space + // Get another chunk size_t grow_chunks_by_words = calc_chunk_size(word_size); Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); @@ -2413,6 +2413,43 @@ return next; } +/* + * The policy is to allocate up to _small_chunk_limit small chunks + * after which only medium chunks are allocated. This is done to + * reduce fragmentation. In some cases, this can result in a lot + * of small chunks being allocated to the point where it's not + * possible to expand. If this happens, there may be no medium chunks + * available and OOME would be thrown. Instead of doing that, + * if the allocation request size fits in a small chunk, an attempt + * will be made to allocate a small chunk. + */ +MetaWord* SpaceManager::get_small_chunk_and_allocate(size_t word_size) { + if (word_size + Metachunk::overhead() > small_chunk_size()) { + return NULL; + } + + MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); + MutexLockerEx cl1(expand_lock(), Mutex::_no_safepoint_check_flag); + + Metachunk* chunk = chunk_manager()->chunk_freelist_allocate(small_chunk_size()); + + MetaWord* mem = NULL; + + if (chunk != NULL) { + // Add chunk to the in-use chunk list and do an allocation from it. + // Add to this manager's list of chunks in use. + add_chunk(chunk, false); + mem = chunk->allocate(word_size); + + inc_used_metrics(word_size); + + // Track metaspace memory usage statistic. + track_metaspace_memory_usage(); + } + + return mem; +} + MetaWord* SpaceManager::allocate(size_t word_size) { MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); @@ -3561,7 +3598,18 @@ } if (result == NULL) { - report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL); + SpaceManager* sm; + if (is_class_space_allocation(mdtype)) { + sm = loader_data->metaspace_non_null()->class_vsm(); + } else { + sm = loader_data->metaspace_non_null()->vsm(); + } + + result = sm->get_small_chunk_and_allocate(word_size); + + if (result == NULL) { + report_metadata_oome(loader_data, word_size, type, mdtype, CHECK_NULL); + } } // Zero initialize.