Excessive memory allocation for primitive arrays in nested resultmaps #927
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
When mapping a result using a resultmap that contains a
byte[]
property and an<association>
mapping, mybatis allocates aByte
object for each byte in the array during the mapping process. This leads to several gigabytes of memory being allocated for the mapping of a 100 megabyte array, which makes the difference between a memory-intensive task and anOutOfMemoryError
.See this repository for a reproduction. The root of the allocation is the
CacheKey
built up inDefaultResultSetHandler#handleRowValuesForNestedResultMap
. This logic inCacheKey#update
results in a boxed object being allocated for each byte in the array value.This logic in CacheKey was introduced in this commit to solve #124 and #125. Arrays use object identity rather than considering they contents for
equals
andhashCode
computations. For cache keys, the later is obviously more desirable, and this is achieved by adding the elements of the array to theupdateList
, rather than the array itself. Unfortunately,java.lang.reflect.Array#get
always allocates a new boxed primitive, circumventing e.g. the caching injava.lang.Byte#valueOf
which is used in 'normal' boxing.The attached commit achieves the content based
equals
andhashCode
by adding a wrapper object around the array, which delegates to the appropriate functions injava.util.Arrays
that consider the contents of the arrays as required.