--- old/src/share/vm/memory/metaspace.cpp 2015-05-16 14:36:37.543192628 -0400 +++ new/src/share/vm/memory/metaspace.cpp 2015-05-16 14:36:36.939158227 -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 @@ -2012,9 +2011,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) { @@ -2061,6 +2059,16 @@ } } +/* + * 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::grow_and_allocate(size_t word_size) { assert(vs_list()->current_virtual_space() != NULL, "Should have been set"); @@ -2082,12 +2090,22 @@ 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); MetaWord* mem = NULL; + if (next == NULL && + word_size + Metachunk::overhead() <= small_chunk_size() && + grow_chunks_by_words == medium_chunk_size()) { + /* + * There are no medium chunks available but a small chunk is big enough. + * See if a small chunk is available. + */ + next = get_new_chunk(word_size, small_chunk_size()); + } + // If a chunk was available, add it to the in-use chunk list // and do an allocation from it. if (next != NULL) {