Changes to make size estimator more accurate. Fixes object size, pointer size
according to architecture and also aligns objects and arrays when computing instance sizes. Verified using Eclipse Memory Analysis Tool (MAT)
This commit is contained in:
parent
1c5ae3edf2
commit
980585b220
|
@ -19,8 +19,6 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||||
* http://www.javaworld.com/javaworld/javaqa/2003-12/02-qa-1226-sizeof.html
|
* http://www.javaworld.com/javaworld/javaqa/2003-12/02-qa-1226-sizeof.html
|
||||||
*/
|
*/
|
||||||
object SizeEstimator {
|
object SizeEstimator {
|
||||||
private val OBJECT_SIZE = 8 // Minimum size of a java.lang.Object
|
|
||||||
private val POINTER_SIZE = 4 // Size of an object reference
|
|
||||||
|
|
||||||
// Sizes of primitive types
|
// Sizes of primitive types
|
||||||
private val BYTE_SIZE = 1
|
private val BYTE_SIZE = 1
|
||||||
|
@ -32,6 +30,28 @@ object SizeEstimator {
|
||||||
private val FLOAT_SIZE = 4
|
private val FLOAT_SIZE = 4
|
||||||
private val DOUBLE_SIZE = 8
|
private val DOUBLE_SIZE = 8
|
||||||
|
|
||||||
|
// Object and pointer sizes are arch dependent
|
||||||
|
val is64bit = System.getProperty("os.arch").contains("64")
|
||||||
|
|
||||||
|
// Size of an object reference
|
||||||
|
// TODO: Get this from jvm/system property
|
||||||
|
val isCompressedOops = Runtime.getRuntime.maxMemory < (Integer.MAX_VALUE.toLong*2)
|
||||||
|
|
||||||
|
// Minimum size of a java.lang.Object
|
||||||
|
val OBJECT_SIZE = if (!is64bit) 8 else {
|
||||||
|
if(!isCompressedOops) {
|
||||||
|
16
|
||||||
|
} else {
|
||||||
|
12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val POINTER_SIZE = if (is64bit && !isCompressedOops) 8 else 4
|
||||||
|
|
||||||
|
// Alignment boundary for objects
|
||||||
|
// TODO: Is this arch dependent ?
|
||||||
|
private val ALIGN_SIZE = 8
|
||||||
|
|
||||||
// A cache of ClassInfo objects for each class
|
// A cache of ClassInfo objects for each class
|
||||||
private val classInfos = new ConcurrentHashMap[Class[_], ClassInfo]
|
private val classInfos = new ConcurrentHashMap[Class[_], ClassInfo]
|
||||||
classInfos.put(classOf[Object], new ClassInfo(OBJECT_SIZE, Nil))
|
classInfos.put(classOf[Object], new ClassInfo(OBJECT_SIZE, Nil))
|
||||||
|
@ -101,10 +121,17 @@ object SizeEstimator {
|
||||||
private def visitArray(array: AnyRef, cls: Class[_], state: SearchState) {
|
private def visitArray(array: AnyRef, cls: Class[_], state: SearchState) {
|
||||||
val length = JArray.getLength(array)
|
val length = JArray.getLength(array)
|
||||||
val elementClass = cls.getComponentType
|
val elementClass = cls.getComponentType
|
||||||
|
|
||||||
|
// Arrays have object header and length field which is an integer
|
||||||
|
var arrSize: Long = alignSize(OBJECT_SIZE + INT_SIZE)
|
||||||
|
|
||||||
if (elementClass.isPrimitive) {
|
if (elementClass.isPrimitive) {
|
||||||
state.size += length * primitiveSize(elementClass)
|
arrSize += alignSize(length * primitiveSize(elementClass))
|
||||||
|
state.size += arrSize
|
||||||
} else {
|
} else {
|
||||||
state.size += length * POINTER_SIZE
|
arrSize += alignSize(length * POINTER_SIZE)
|
||||||
|
state.size += arrSize
|
||||||
|
|
||||||
if (length <= ARRAY_SIZE_FOR_SAMPLING) {
|
if (length <= ARRAY_SIZE_FOR_SAMPLING) {
|
||||||
for (i <- 0 until length) {
|
for (i <- 0 until length) {
|
||||||
state.enqueue(JArray.get(array, i))
|
state.enqueue(JArray.get(array, i))
|
||||||
|
@ -176,9 +203,16 @@ object SizeEstimator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shellSize = alignSize(shellSize)
|
||||||
|
|
||||||
// Create and cache a new ClassInfo
|
// Create and cache a new ClassInfo
|
||||||
val newInfo = new ClassInfo(shellSize, pointerFields)
|
val newInfo = new ClassInfo(shellSize, pointerFields)
|
||||||
classInfos.put(cls, newInfo)
|
classInfos.put(cls, newInfo)
|
||||||
return newInfo
|
return newInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def alignSize(size: Long): Long = {
|
||||||
|
val rem = size % ALIGN_SIZE
|
||||||
|
return if (rem == 0) size else (size + ALIGN_SIZE - rem)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue