As far as I can see java.lang.instrument.Instrumentation.getSize
returns the size without elements (as the size doesn't depend on the number of the list. It is 24 bytes). Looks strange. Is that correct that list items are not measured?

- 1,642
- 3
- 19
- 36
-
Possible duplicate of [In Java, what is the best way to determine the size of an object?](https://stackoverflow.com/questions/52353/in-java-what-is-the-best-way-to-determine-the-size-of-an-object) – Progman Jan 12 '19 at 18:55
-
..it depends on the list implementation, I'd say ...where for a "linked list" (e.g.) 24 bytes sounds quite ok. ...for an "array list", i would expect the full load + some overhead/buffer. – xerx593 Jan 12 '19 at 19:20
1 Answers
The size of objects in Java is fixed, because Java, like C++, is a statically-typed language. The size basically corresponds to whatever is written inside the class
file. Since a class
file layout is fixed, so is its size.
An ArrayList
for example, looks roughly like this:
public class ArrayList implements List
{
Object[] elementData;
private int size;
}
The size of any ArrayList
instance would be the size of elementData
(a pointer to Object[]
), size
(an int
), and overhead. So 24 sounds about right.
That is often referred to as a shallow size.
It sounds like what you want instead is the deep size, i.e. the size of the List + all of the objects it refers to + all the objects those objects refer to, etc.
That's not directly possible using instrumentation API, but with some hacky reflection + instrumentation you might be able to get it. The basic idea is to reflect the object and recursively call getObjectSize()
on all referred objects, skipping circular references.
Something along the lines:
public class DeepSizeCounter {
private HashSet<Object> counted = new HashSet<>();
private long size = 0;
public long getSizeDeep(Object x) throws Exception {
counted.clear();
size = 0;
computeSizeDeep(x);
return size;
}
private void computeSizeDeep(Object x) throws Exception {
if (x != null && !counted.contains(x)) {
counted.add(x);
size += instrumentation.getObjectSize(x);
if (x.getClass().isArray()) {
if (!x.getClass().getComponentType().isPrimitive())
for (Object y : (Object[]) x)
computeSizeDeep(y);
} else {
for (Field f : x.getClass().getDeclaredFields()) {
if (!f.getType().isPrimitive() && (f.getModifiers() & Modifier.STATIC) == 0) {
f.setAccessible(true);
computeSizeDeep(f.get(x));
}
}
}
}
}
}
Use as:
long totalSize = new DeepSizeCounter().getSizeDeep(myList);
Beware that this approach is unreliable because objects can have backreferences to some global state which you can't distinguish automatically, so can end up counting way too many objects. Also if access control is on, the Field.setAccessible()
hack won't work and you won't be able to count any non-public members.

- 80,671
- 25
- 200
- 267
-
Thank you, and what about an array of primitives? Is it correct to measure each element using instrumentation.getObjectSize(x)? I suppose yes, if not primitives, but Wrappers are stored. Bu as array class is native, we can't check it. – Ekaterina Jan 13 '19 at 15:13
-
1Arrays of primitive just work: `getObjectSize(new int[1000])` returns `4016`. – rustyx Jan 13 '19 at 15:55