Calculate Size of Object in Java

Calculate size of Object in Java

You can use the java.lang.instrumentation package.

It has a method that can be used to get the implementation specific approximation of object size, as well as overhead associated with the object.

The answer that Sergey linked has a great example, which I'll repost here, but you should have already looked at from his comment:

import java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
private static Instrumentation instrumentation;

public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}

public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
}

Use getObjectSize:

public class C {
private int x;
private int y;

public static void main(String [] args) {
System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
}
}

Source

In Java, what is the best way to determine the size of an object?

You can use the java.lang.instrument package.

Compile and put this class in a JAR:

import java.lang.instrument.Instrumentation;

public class ObjectSizeFetcher {
private static Instrumentation instrumentation;

public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}

public static long getObjectSize(Object o) {
return instrumentation.getObjectSize(o);
}
}

Add the following to your MANIFEST.MF:

Premain-Class: ObjectSizeFetcher

Use the getObjectSize() method:

public class C {
private int x;
private int y;

public static void main(String [] args) {
System.out.println(ObjectSizeFetcher.getObjectSize(new C()));
}
}

Invoke with:

java -javaagent:ObjectSizeFetcherAgent.jar C

Is there a simple way to get the size of a java object?

There is an opensource java.SizeOf project that determines size of any of your Java object in memory.

What is the size of the object in java

The in-memory size of the object depends on the architecture, mainly on whether the VM is 32 or 64-bit. The actual VM implementation also matters.

For each object, you need space for its object header (typically 2*8 bytes on 64-bit VMs), its fields (extra space for alignment depending on the VM implementation). The final space is then rounded up to the nearest multiple of the word size.

sizeof Java object

The question is not meaningful, at least not without further context.

The notion of "size" in Java is only reasonably well defined for primitives: A byte is 8 bit (unsurprisingly) an int is 32 bit, a long 64bit, etc. (see e.g. http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html for a full list).

For object instances, it's more complicated, because:

  • Object instances can (and usually will) contain references to other instances internally, so you must decide whether to count these dependent instances, and how. What if several instances share a dependency?
  • Sometimes, object instances may be reused (e.g. interning of java.lang.String, see http://en.wikipedia.org/wiki/String_interning ). So if you use x objects of size y, the total size may be smaller than x*y
  • The JVM has a lot of leeway about how to implement objects and instances internally.
    It may use different techniques for different instances (e.g. sharing internal data structures), so there may not even be a meaningful "size" to assign to a single object.

Maybe you could explain why you are interested in object sizes.

There are some rules of thumb for estimating the heap memory used by instances (e.g. in the Sun JVM, a java.lang.Object instance uses 8 byte), but these will depend on the JVM you use.

Generally, if you want to know about your heap usage, use a memory / heap profiler.

Edit:

Well, there is (as of JDK 6) a way to get an approximation of the amount of memory used by an object: http://download.oracle.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html#getObjectSize%28java.lang.Object%29

It's still only an approximation...

Where to find the evidence of how to calculate the size of a java object

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

Java object memory size of a set of strings

Because I have no life, I present the results of boredom. Note that this is pretty much guaranteed to be inaccurate, due stupid mistakes and such. Used this for help, but I'm not too sure on accuracy. I could read the JVM specifications, but I don't have that much free time on my hands.

This calculation gets pretty complicated due to the multitude of fields that exist inside the objects of concern, plus some uncertainty on my part about how much overhead there is for objects and where padding goes. If memory serves, objects have 8 bytes reserved for the header. This is all for a 64-bit VM, by the way. Only difference between that and a 32-bit VM is the size of references, I think.

Summary of how to do this: Obtain source code, and recursively add up space needed for all fields. Need knowledge of how VM works and how implementations work.

Starting from a String. String defines:

  1. Object header - 8 bytes
  2. long serialVersionUID - 8 bytes
  3. int hash - 4 bytes + 4 bytes padding
  4. char[] value (set to a char[10] in your case) - 8 bytes for reference
  5. ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0] - 8 bytes for reference

char[10] defines:

  1. Object header - 8 bytes
  2. int length - 4 bytes
  3. char x10 - 2 bytes * 10 = 20 bytes

ObjectStreamField[0] defines:

  1. Object header - 8 bytes
  2. int length - 4 bytes + 4 bytes padding

Total for a single String with length 10: 88 bytes

Total for 1000 Strings with length 10: 88000 bytes.


HashSet defines:

  1. Object header - 8 bytes
  2. long serialVersionUID - 8 bytes
  3. Object PRESENT - 8 bytes
  4. HashMap<E, Object> map - 8 bytes

HashMap defines (in Java 8) (ignoring things that are created on demand, like EntrySet):

  1. Object header - 8 bytes
  2. long serialVersionUID - 8 bytes
  3. int DEFAULT_INITIAL_CAPACITY - 4 bytes
  4. int MAXIMUM_CAPACITY - 4 bytes
  5. int TREEIFY_THRESHOLD - 4 bytes
  6. int UNTREEIFY_THRESHOLD - 4 bytes
  7. int MIN_TREEIFY_CAPACITY - 4 bytes
  8. int size - 4 bytes
  9. int modcount - 4 bytes
  10. int threshold - 4 bytes
  11. float DEFAULT_LOAD_FACTOR - 4 bytes
  12. float loadFactor - 4 bytes
  13. Node<K, V>[] table - 8 bytes

Node defines:

  1. Object header - 8 bytes
  2. int hash - 4 bytes + 4 bytes padding
  3. K key - 8 bytes
  4. V value - 8 bytes
  5. Node<K, V> next - 8 bytes

Node<K, V>[] should have a size of 2048, if I remember how HashMap works. So it defines:

  1. Object header - 8 bytes
  2. int length - 4 bytes + 4 bytes padding
  3. Node<K, V> reference * 2048 - 8 bytes * 2048 = 16384 bytes.

So the HashSet should be:

  1. 32 bytes for just HashSet
  2. 64 bytes for just HashMap
  3. 40 bytes per Node<K, V> inside Node<K, V>[] * 1000 nodes = 40000 bytes
  4. 16400 bytes for Node<K, V>[] inside the HashMap

Total: 56496 bytes for the HashSet, without taking into account the String contents


So at least by my calculations, the total space taken should be somewhere around 144496 bytes -- about 141 kilobytes (kibibytes for the pedantic). To be honest, this seems like it's more than a bit on the small side, but it's a start.

I can't get the Instrumentation interface working at the moment, so I can't double-check. But if someone knows what he/she is doing a comment pointing out my mistakes would be welcome.



Related Topics



Leave a reply



Submit