2

I've searched about the size of a java object for a long time, there are a lot of answers like this, everyone is telling me that the size of the overhead of a java object, and how to calculate out the actual size. But how do they know that? I did not find any evidence from the official oracle documents. What is the evidence for that conclusion? Or the data was just come from some guesses based on some experiments?

Another thing. It is mentioned in the official document that there is a 'approximative' way to measure the object - the Instrumentation way, can anybody explain to me what is the 'approximately' means? When it is accurate, when it is not. Better to have the evidence.

Community
  • 1
  • 1
dawnstar
  • 507
  • 5
  • 10

4 Answers4

5

how to calculate out the actual size. But how do they know that?

from experience.

I did not find any evidence from the official oracle documents.

Its up to the JVM. For OpenJDK based JVMs, 32-bit JVM has a different header size to 64-bit JVM as the header contains a reference. Other JVMs could be different again.

Or the data was just come from some guesses based on some experiments?

Essentially, yes.

can anybody explain to me what is the 'approximately' means?

When you measure the size of an object it can means many different things

  • How big is the object? (Shallow depth)
  • How much memory does it use? (Object allocation is 8-byte aligned i.e. always a multiple of 8)
  • How much space does the object and all the objects referenced use? (Deep depth)
  • How much space might be freed if it were discarded? (how many objects are shared and does it appear in the middle of two fragments of freed memory)
  • Do you count the space used on the stack, or space used in off heap memory?

Given you can have many difference answers depending on what you need to know, it is useful to have one number which is approximately close to all of these which you use for calculations.


Where you get a problem using Runtime is that the TLAB allocated data in large blocks. These large blocks can be further allocated in a multi-thread way. The downside is you don't get accurate memory used information.

static long memTaken() {
    final Runtime rt = Runtime.getRuntime();
    return rt.totalMemory() - rt.freeMemory();
}

public static void main(String... args) {
    long used1 = memTaken();
    Float i = new Float(0);
    long used2 = memTaken();
    System.out.println("new Float(0) used "+(used2 - used1)+" bytes.");
}

run without options

new Float(0) used 0 bytes.

Turn off the TLAB and you see with -XX:-UseTLAB

new Float(0) used 336 bytes.

This is much higher than you might expect because the class itself had to be loaded. If you create one instance of a Float first by adding to the start

Float j = new Float(1);

you get

new Float(0) used 16 bytes
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • And if you allocate 10k objects or more, the TLAB effect would fade away? That would be the reason why I didn't observe it. What's the granularity of TLABs? – Marko Topolnik Sep 03 '12 at 12:02
  • The size of the TLAB is tuned by the JVM and can vary. The effect fades away but never disappears completely. ;) – Peter Lawrey Sep 03 '12 at 12:07
  • For example, I want to read the values from a Array of objects, what is the size it takes into the cpu cache? My assumption is: Shallow depth(when the operation refer to the inside object it will be Deep depth), and 8-byte aligned. Is that right? – dawnstar Sep 03 '12 at 23:32
  • @dawnstar Its worth remembering you can't have an array of objects in Java. You can have an array of references to objects. The array will be continuous in memory and the objects are likely to be next to the array if they are created at the same time. Each object has its own overhead. The upside of this is that you can discard or retain any object without messing up the garbage collection. – Peter Lawrey Sep 04 '12 at 06:57
2

I think the answer can only be empirical as it is implementation dependent:

The Java virtual machine does not mandate any particular internal structure for objects.

assylias
  • 321,522
  • 82
  • 660
  • 783
1

For me the best method is the most down-to-earth one, using

long memTaken() {
  final Runtime rt = Runtime.getRuntime();
  return rt.totalMemory() - rt.freeMemory();
}
  1. Remember initial memTaken();
  2. Make an array of a million object (adapt this number to fit your heap);
  3. Subtract memTaken() from the remembered one.

There may be some transient allocation in the process, so you also need to run the GC. There are no guarantees provided by System.gc(), but this approach has always worked for me:

for (int i = 0; i < 3; i++) { System.gc(); Thread.sleep(50); }

You must be careful to ensure this gives stable results. For example, an approach is to calculate memory load for several different object counts and compare results. They should all match on the memory/instance answer they give.

I have advised this before, been put down for the lame solution, been recommended to use proper tooling, etc. So I used tooling, for example jvisualvm—and it gave wrong results. This method has never given wrong results to me.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • The first method produces more accurate results if you turn off the TLAB with `-XX:-UseTLAB` otherwise memory is allocated to threads in large blocks so you will see zero difference followed by large lumps of memory used. – Peter Lawrey Sep 03 '12 at 11:34
  • I have never actually observed this effect, but I don't know the details on why not. – Marko Topolnik Sep 03 '12 at 11:36
  • I added a section to my answer demonstrating the problem and the workaround. – Peter Lawrey Sep 03 '12 at 11:51
0

there are two different sizes for java objects: the shallow size and the retained size. the shallow size of an object is the sum of sizes of all it's fields: straight-forward for primitive members, and the size of a pointer for every non-primitive member(and this varies between 32 & 64 bit architectures). you can find the shallow size of an object at runtime using instrumantation. here is a nice tutorial

retained size is defined by the heap space that will be freed when the object is garbaged. finding the retained size of an object is not trivial, mainly because objects are usually composed of other objects. for example:

public class Clazz {

    public byte[] member;

    public static void main(String[] args) {
        byte[] bytes = new byte[128];
        Clazz a = new Clazz();
        Clazz b = new Clazz();
        a.member = bytes;
        b.member = bytes;
    }
}

what is the retained size of a? and b? use a profiler to compute retained size (most profilers are using static heap analysis for that).

iGili
  • 823
  • 7
  • 18