How to determine the size of an object in Java
Asked Answered
V

29

687

I have an application that reads a CSV file with piles of data rows. I give the user a summary of the number of rows based on types of data, but I want to make sure that I don't read in too many rows of data and cause OutOfMemoryErrors. Each row translates into an object. Is there a way to find out the size of that object programmatically? Is there a reference that defines how large primitive types and object references are for a VM?

Right now, I have code that says read up to 32,000 rows, but I'd also like to have code that says read as many rows as possible until I've used 32MB of memory.

Vestiary answered 9/9, 2008 at 17:7 Comment(1)
I added my Agent with mvn configs and explained how here: https://mcmap.net/q/64761/-how-to-put-classes-for-javaagent-in-the-classpathInfantry
C
491

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
Culbertson answered 9/9, 2008 at 19:24 Comment(17)
@Stefan Nice hint! Can you please tell, what will be the size of byte[0], byte[1], byte[5], int[0], int[1], int[2] using the approach you described? It would be nice, if results include overhead for length of array and memory alignment.Moazami
I tried this and got strange and unhelpful results. Strings were always 32, regardless of size. I thought this was maybe the pointer size but for another immutable class I created, I got 24. It works well for primitives but then you don't really need a program to tell you how big a char is.Licastro
@Licastro this solution is only an "approximation of the amount of storage consumed by the specified object", as specified in the documentation. Also I suppose that the authors decided to set the size of a String as 32 bytes (only the pointer?) because of the Java's String pool, which makes it difficult to say, whether a String instance is shared (stored in the pool) or local&unique to a class.Skirt
How I can user ObjectSizeFetcher, if don't export jar? I have test java project in eclipse.Salimeter
what if I am using tomcat, is it the same? When I add the Premain-Class: ObjectSizeFetcher to the MANIFEST.MF in the webcontent->meta-inf->manifest.mf, and I run a scheduler to check my size of the object in ecplise, exception of "Illegal access: this web application instance has been stopped already. Could not load wodinow.weixin.jaskey.util.ObjectSizeFetcher. The Exception is java.lang.IllegalStateException" is thrownQuintie
What will the size of an object be if it holds two maps such that the contents of the first map is inserted into the second map as-is by iterating over the first map i.e, map2.put(map1.key1,map1.value1), map2.put(map1.key2,map1.value2).. and so on. I tried this out and looks like the program is written in a way such that it calculates the size of both the maps even though the second map only contains references to the contents of the first mapHallucinate
Where is ObjectSizeFetcherAgent.jar coming from?Azole
Example on my GitHub for you to play with. As mentioned by others, the size calculation is not recursive, e.g. byte[] members count only as a single pointer.Strick
These results seem way off. I deserialized a large CSV into a List<List<String>>. Looped through each item and summed up the size. ObjectSizeOf reported 7.5MB. The source file was 119.6MB! The in-use memory went up by 154MB when I loaded the file, after looping GC calls with pauses in between. Not sure how Instrumentation does its thing, but you might want to verify the numbers you get.Agamete
There must be something not quite right with this approach when trying to find my web session size: it reports 40, while ObjectGraphMeasurer (github.com/DimitrisAndreou/memory-measurer) reports "Footprint{Objects=34, References=52, Primitives=[float, int x 19, char x 257, long x 2, byte x 68557]}". ObjectGraphMeasurer is clearly the winner.Sulcate
for those who have forgotten, to add the manifest to the jar use jar -cvfm ObjectSizeFetcherAgent.jar mymanifest.txt C.class populate mymanifest.txt with what you need eg a Premain-ClassYaroslavl
@YShinkarev The documentation doesn't describe a way of doing this without a jar file. Only this "-javaagent:jarpath[=options]"Spiderwort
JDK contains java.lang.instrument package since jdk 1.5Lorenzalorenzana
What are the side effects when you launch a JVM with this instrumentation agent attached? Performance impact? Memory impact?Yearling
@brel The reason a String is only 32 bytes regardless of actual length is because the variable length part of a string is stored in a char[], which is it's own object. To get the true size of an object, you need to add the size of itself and the size of each object it references.Scrawl
Another good example here: baeldung.com/java-size-of-objectLooseleaf
this method used to work with JDK17 (and earlier) but with JDK20 it throws exception (at least for me): #77055955. has anyone gotten it to work with JDK20? would like to know.Apace
S
170

You should use jol, a tool developed as part of the OpenJDK project.

JOL (Java Object Layout) is the tiny toolbox to analyze object layout schemes in JVMs. These tools are using Unsafe, JVMTI, and Serviceability Agent (SA) heavily to decoder the actual object layout, footprint, and references. This makes JOL much more accurate than other tools relying on heap dumps, specification assumptions, etc.

To get the sizes of primitives, references and array elements, use VMSupport.vmDetails(). On Oracle JDK 1.8.0_40 running on 64-bit Windows (used for all following examples), this method returns

Running 64-bit HotSpot VM.
Using compressed oop with 0-bit shift.
Using compressed klass with 3-bit shift.
Objects are 8 bytes aligned.
Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

You can get the shallow size of an object instance using ClassLayout.parseClass(Foo.class).toPrintable() (optionally passing an instance to toPrintable). This is only the space consumed by a single instance of that class; it does not include any other objects referenced by that class. It does include VM overhead for the object header, field alignment and padding. For java.util.regex.Pattern:

java.util.regex.Pattern object internals:
 OFFSET  SIZE        TYPE DESCRIPTION                    VALUE
      0     4             (object header)                01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000)
      4     4             (object header)                00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
      8     4             (object header)                cb cf 00 20 (1100 1011 1100 1111 0000 0000 0010 0000)
     12     4         int Pattern.flags                  0
     16     4         int Pattern.capturingGroupCount    1
     20     4         int Pattern.localCount             0
     24     4         int Pattern.cursor                 48
     28     4         int Pattern.patternLength          0
     32     1     boolean Pattern.compiled               true
     33     1     boolean Pattern.hasSupplementary       false
     34     2             (alignment/padding gap)        N/A
     36     4      String Pattern.pattern                (object)
     40     4      String Pattern.normalizedPattern      (object)
     44     4        Node Pattern.root                   (object)
     48     4        Node Pattern.matchRoot              (object)
     52     4       int[] Pattern.buffer                 null
     56     4         Map Pattern.namedGroups            null
     60     4 GroupHead[] Pattern.groupNodes             null
     64     4       int[] Pattern.temp                   null
     68     4             (loss due to the next object alignment)
Instance size: 72 bytes (reported by Instrumentation API)
Space losses: 2 bytes internal + 4 bytes external = 6 bytes total

You can get a summary view of the deep size of an object instance using GraphLayout.parseInstance(obj).toFootprint(). Of course, some objects in the footprint might be shared (also referenced from other objects), so it is an overapproximation of the space that could be reclaimed when that object is garbage collected. For the result of Pattern.compile("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$") (taken from this answer), jol reports a total footprint of 1840 bytes, of which only 72 are the Pattern instance itself.

java.util.regex.Pattern instance footprint:
     COUNT       AVG       SUM   DESCRIPTION
         1       112       112   [C
         3       272       816   [Z
         1        24        24   java.lang.String
         1        72        72   java.util.regex.Pattern
         9        24       216   java.util.regex.Pattern$1
        13        24       312   java.util.regex.Pattern$5
         1        16        16   java.util.regex.Pattern$Begin
         3        24        72   java.util.regex.Pattern$BitClass
         3        32        96   java.util.regex.Pattern$Curly
         1        24        24   java.util.regex.Pattern$Dollar
         1        16        16   java.util.regex.Pattern$LastNode
         1        16        16   java.util.regex.Pattern$Node
         2        24        48   java.util.regex.Pattern$Single
        40                1840   (total)

If you instead use GraphLayout.parseInstance(obj).toPrintable(), jol will tell you the address, size, type, value and path of field dereferences to each referenced object, though that's usually too much detail to be useful. For the ongoing pattern example, you might get the following. (Addresses will likely change between runs.)

java.util.regex.Pattern object externals:
          ADDRESS       SIZE TYPE                             PATH                           VALUE
         d5e5f290         16 java.util.regex.Pattern$Node     .root.next.atom.next           (object)
         d5e5f2a0        120 (something else)                 (somewhere else)               (something else)
         d5e5f318         16 java.util.regex.Pattern$LastNode .root.next.next.next.next.next.next.next (object)
         d5e5f328      21664 (something else)                 (somewhere else)               (something else)
         d5e647c8         24 java.lang.String                 .pattern                       (object)
         d5e647e0        112 [C                               .pattern.value                 [^, [, a, -, z, A, -, Z, 0, -, 9, _, ., +, -, ], +, @, [, a, -, z, A, -, Z, 0, -, 9, -, ], +, \, ., [, a, -, z, A, -, Z, 0, -, 9, -, ., ], +, $]
         d5e64850        448 (something else)                 (somewhere else)               (something else)
         d5e64a10         72 java.util.regex.Pattern                                         (object)
         d5e64a58        416 (something else)                 (somewhere else)               (something else)
         d5e64bf8         16 java.util.regex.Pattern$Begin    .root                          (object)
         d5e64c08         24 java.util.regex.Pattern$BitClass .root.next.atom.val$rhs        (object)
         d5e64c20        272 [Z                               .root.next.atom.val$rhs.bits   [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64d30         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d48         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d60         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64d78         24 java.util.regex.Pattern$1        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e64d90         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e64da8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64dc0         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs.val$lhs (object)
         d5e64dd8         24 java.util.regex.Pattern$5        .root.next.atom.val$lhs        (object)
         d5e64df0         24 java.util.regex.Pattern$5        .root.next.atom                (object)
         d5e64e08         32 java.util.regex.Pattern$Curly    .root.next                     (object)
         d5e64e28         24 java.util.regex.Pattern$Single   .root.next.next                (object)
         d5e64e40         24 java.util.regex.Pattern$BitClass .root.next.next.next.atom.val$rhs (object)
         d5e64e58        272 [Z                               .root.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e64f68         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e64f80         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e64f98         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs.val$lhs (object)
         d5e64fb0         24 java.util.regex.Pattern$1        .root.next.next.next.atom.val$lhs.val$rhs (object)
         d5e64fc8         24 java.util.regex.Pattern$5        .root.next.next.next.atom.val$lhs (object)
         d5e64fe0         24 java.util.regex.Pattern$5        .root.next.next.next.atom      (object)
         d5e64ff8         32 java.util.regex.Pattern$Curly    .root.next.next.next           (object)
         d5e65018         24 java.util.regex.Pattern$Single   .root.next.next.next.next      (object)
         d5e65030         24 java.util.regex.Pattern$BitClass .root.next.next.next.next.next.atom.val$rhs (object)
         d5e65048        272 [Z                               .root.next.next.next.next.next.atom.val$rhs.bits [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]
         d5e65158         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$lhs (object)
         d5e65170         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs.val$rhs (object)
         d5e65188         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$lhs (object)
         d5e651a0         24 java.util.regex.Pattern$1        .root.next.next.next.next.next.atom.val$lhs.val$lhs.val$rhs (object)
         d5e651b8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs.val$lhs (object)
         d5e651d0         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom.val$lhs (object)
         d5e651e8         24 java.util.regex.Pattern$5        .root.next.next.next.next.next.atom (object)
         d5e65200         32 java.util.regex.Pattern$Curly    .root.next.next.next.next.next (object)
         d5e65220        120 (something else)                 (somewhere else)               (something else)
         d5e65298         24 java.util.regex.Pattern$Dollar   .root.next.next.next.next.next.next (object)

The "(something else)" entries describe other objects in the heap that are not part of this object graph.

The best jol documentation is the jol samples in the jol repository. The samples demonstrate common jol operations and show how you can use jol to analyze VM and garbage collector internals.

Starry answered 4/5, 2015 at 0:46 Comment(5)
This answer should have more upvotes. Definitely a very good option to check. EDIT: Checked that this was added this year while question was asked in '08. Probably the best and easiest option to do what OP asked at the moment.Gipon
The tool author wrote a blog post about Jol.Ophthalmology
To determine size of Object "obj" use:org.openjdk.jol.info.GraphLayout.parseInstance(obj).totalSize();Maegan
Note that vmDetails is now VM.current().details().Tanka
Check out GraphLayout.parseInstance(instance).toFootprint() I found it more useful to understand object sizesTonina
T
124

I accidentally found a java class "jdk.nashorn.internal.ir.debug.ObjectSizeCalculator", already in jdk, which is easy to use and seems quite useful for determining the size of an object.

System.out.println(ObjectSizeCalculator.getObjectSize(new gnu.trove.map.hash.TObjectIntHashMap<String>(12000, 0.6f, -1)));
System.out.println(ObjectSizeCalculator.getObjectSize(new HashMap<String, Integer>(100000)));
System.out.println(ObjectSizeCalculator.getObjectSize(3));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[]{1, 2, 3, 4, 5, 6, 7 }));
System.out.println(ObjectSizeCalculator.getObjectSize(new int[100]));

results:

164192
48
16
48
416
Tonsillectomy answered 9/9, 2016 at 7:53 Comment(6)
Same here, I was trying the other solutions proposed above and came across ObjectSizeCalculator. I believe no one mentioned if before since it was recently introduced on the JDK 8 as part of the project Nashorn. However I haven't found any official documentation about this class on the web.Walling
It doesn't seem to consider string lengths. Is it just about size on the stack?Roseliaroselin
I have a hashmap, where com.carrotsearch.RamUsageEstimator returns about the half of ObjectSizeCalculator. Which one is true? - Which one is more relieable?Dopp
Note that ObjectSizeCalculator is only supported on HotSpot VMBurdick
Also jdk.nashorn.internal.ir.debug.ObjectSizeCalculator is no longer present on JDK 11Wotan
Using something that has "internal" in its name will always end up in tears. Like this one, for example.Irena
H
82

Some years back Javaworld had an article on determining the size of composite and potentially nested Java objects, they basically walk through creating a sizeof() implementation in Java. The approach basically builds on other work where people experimentally identified the size of primitives and typical Java objects and then apply that knowledge to a method that recursively walks an object graph to tally the total size.

It is always going to be somewhat less accurate than a native C implementation simply because of the things going on behind the scenes of a class but it should be a good indicator.

Alternatively a SourceForge project appropriately called sizeof that offers a Java5 library with a sizeof() implementation.

P.S. Do not use the serialization approach, there is no correlation between the size of a serialized object and the amount of memory it consumes when live.

Hackberry answered 9/9, 2008 at 18:42 Comment(2)
The sizeof utility is probably the fastest way. It's basically what Stefan said, but already packed in a jar ready to use.Morel
the link in the answer is brokenDevinna
W
75

Firstly "the size of an object" isn't a well-defined concept in Java. You could mean the object itself, with just its members, the Object and all objects it refers to (the reference graph). You could mean the size in memory or the size on disk. And the JVM is allowed to optimise things like Strings.

So the only correct way is to ask the JVM, with a good profiler (I use YourKit), which probably isn't what you want.

However, from the description above it sounds like each row will be self-contained, and not have a big dependency tree, so the serialization method will probably be a good approximation on most JVMs. The easiest way to do this is as follows:

 Serializable ser;
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 ObjectOutputStream oos = new ObjectOutputStream(baos);
 oos.writeObject(ser);
 oos.close();
 return baos.size();

Remember that if you have objects with common references this will not give the correct result, and size of serialization will not always match size in memory, but it is a good approximation. The code will be a bit more efficient if you initialise the ByteArrayOutputStream size to a sensible value.

Waterfowl answered 9/9, 2008 at 17:22 Comment(7)
I like this approach. How far off in terms of object size have you been off.Stephie
Very simple and effective. Other methods are too messy (specially inside of Eclipse RCP). Thanks.Ophthalmoscope
Serialization won't keep track of transient variables, and the default serialization method writes strings in UTF-8, so any ANSI characters will only take one byte. If you have many strings, your size will be so far off as to be useless.Empyrean
while this may not give the exact size, for my needs I only needed a comparison between 2 object and SizeOf won't initialize from a web app. Thanks!Sagacious
Good recommendation of YourKit. Other alternatives are VirtualVM and jvmmonitorBocock
Most importantly, the OP wants to know the size of his Objects to avoid hitting a memory ceiling. I do not thing writing the objects to a byte array (and therefore doubling memory consumption) really helps with the original problem.Atc
Serialization doesn't seem to be a good suggestion https://mcmap.net/q/63594/-how-to-determine-the-size-of-an-object-in-javaBirdman
C
39

If you would just like to know how much memory is being used in your JVM, and how much is free, you could try something like this:

// Get current size of heap in bytes
long heapSize = Runtime.getRuntime().totalMemory();

// Get maximum size of heap in bytes. The heap cannot grow beyond this size.
// Any attempt will result in an OutOfMemoryException.
long heapMaxSize = Runtime.getRuntime().maxMemory();

// Get amount of free memory within the heap in bytes. This size will increase
// after garbage collection and decrease as new objects are created.
long heapFreeSize = Runtime.getRuntime().freeMemory();

edit: I thought this might be helpful as the question author also stated he would like to have logic that handles "read as many rows as possible until I've used 32MB of memory."

Coterie answered 9/9, 2008 at 17:19 Comment(6)
This is not a good solution, as you never know when a garbage collect will happen, or how much extra memory will be allocated to the heap at once.Waterfowl
That is true, and I wouldn't intend this to address the main question of this post, but it might help him to know programmatically when he is getting somewhat close to hitting the max heap size.Coterie
Other problem of this solution is when you are in a multi-thread environment (like in a web server). It's possible that other threads was in execution and consuming memory. With this approximation your are calculating used memory in all the virtual machine.Bocock
Another disadvantage is that freeMemory returns an approximation. Try creating a javax.crypto.Cipher object. The difference between two calls to freeMemory (to estimate the size of a Cipher) is not constant !Dentist
Hello, why does heapSize +heapFreeSize <heapMaxSize ?Quintie
I believe you can force a garbage collection, so you can do some stuff in this approach.Unfriended
P
27

Back when I worked at Twitter, I wrote a utility for calculating deep object size. It takes into account different memory models (32-bit, compressed oops, 64-bit), padding, subclass padding, works correctly on circular data structures and arrays. You can just compile this one .java file; it has no external dependencies:

https://github.com/twitter/commons/blob/master/src/java/com/twitter/common/objectsize/ObjectSizeCalculator.java

Preengage answered 9/4, 2015 at 11:7 Comment(5)
Szia! I'd just like to shout out your presentation too: slides 15-20 are great to help get an instinctive feel for the cost of various data-structure decisions. Thanks for posting that!Alarise
"it has no external dependencies" - since when is guava not an external dependency?Exocarp
looks very similar to github.com/JetBrains/jdk8u_nashorn/blob/master/src/jdk/nashorn/… ? :OGuth
Guave is an external dependency.Estey
This solution does not work when using OpenJDK 17Hooknosed
F
24

When using JetBrains IntelliJ, first enable "Attach memory agent" in File | Settings | Build, Execution, Deployment | Debugger.

When debugging, right-click a variable of interest and choose "Calculate Retained Size": Calculate Retained Size

Flywheel answered 23/4, 2020 at 21:30 Comment(3)
I don't see this in my Intellij - using 2019.2. What version are you using?Batchelder
Got an error with this one: Connected to the target VM, address: '127.0.0.1:49538', transport: 'socket' JDWP exit error AGENT_ERROR_OUT_OF_MEMORY(188): PushLocalFrame: Unable to push JNI frame [src/jdk.jdwp.agent/share/native/libjdwp/util.c:1560] FATAL ERROR in native method: JDWP PushLocalFrame: Unable to push JNI frame, jvmtiError=AGENT_ERROR_OUT_OF_MEMORY(188) Disconnected from the target VM, address: '127.0.0.1:49538', transport: 'socket' Process finished with exit code 134 (interrupted by signal 6: SIGABRT)Thies
I am using Android Studio Bumblebee (2021.1.1) and the Calculate Retained Size is not shown. Even after checking Attach memory agent in options. Is it included in AS? I found it in Intellij docs.Areta
S
23

Much of the other answers provide shallow sizes - e.g. the size of a HashMap without any of the keys or values, which isn't likely what you want.

The jamm project uses the java.lang.instrumentation package above but walks the tree and so can give you the deep memory use.

new MemoryMeter().measureDeep(myHashMap);

https://github.com/jbellis/jamm

To use MemoryMeter, start the JVM with "-javaagent:/jamm.jar"

Sw answered 6/3, 2015 at 14:7 Comment(0)
D
12

You have to walk the objects using reflection. Be careful as you do:

  • Just allocating an object has some overhead in the JVM. The amount varies by JVM so you might make this value a parameter. At least make it a constant (8 bytes?) and apply to anything allocated.
  • Just because byte is theoretically 1 byte doesn't mean it takes just one in memory.
  • There will be loops in object references, so you'll need to keep a HashMap or somesuch using object-equals as the comparator to eliminate infinite loops.

@jodonnell: I like the simplicity of your solution, but many objects aren't Serializable (so this would throw an exception), fields can be transient, and objects can override the standard methods.

Diastasis answered 9/9, 2008 at 17:19 Comment(3)
Aren't the sizes of various primitives defined in the Java Specification? (§2.4.1)Guay
Not in the sense of "how much memory does it occupy," which is the question. Only in the sense of how they operate. For example, bytes, chars, and shorts take up an entire word on the Java stack, even though they operate with rounding etc..Diastasis
This sounds similar to measuring the size, as shown by Heinz in his Newsletter #78: javaspecialists.eu/archive/Issue078.html. I used it. His approach works.Peony
G
12

You have to measure it with a tool, or estimate it by hand, and it depends on the JVM you are using.

There is some fixed overhead per object. It's JVM-specific, but I usually estimate 40 bytes. Then you have to look at the members of the class. Object references are 4 (8) bytes in a 32-bit (64-bit) JVM. Primitive types are:

  • boolean and byte: 1 byte
  • char and short: 2 bytes
  • int and float: 4 bytes
  • long and double: 8 bytes

Arrays follow the same rules; that is, it's an object reference so that takes 4 (or 8) bytes in your object, and then its length multiplied by the size of its element.

Trying to do it programmatically with calls to Runtime.freeMemory() just doesn't give you much accuracy, because of asynchronous calls to the garbage collector, etc. Profiling the heap with -Xrunhprof or other tools will give you the most accurate results.

Guay answered 9/9, 2008 at 17:20 Comment(3)
@Guay I wouldn't be sure about sizeof(boolean)==1 looking at this thread (#1907818). Can you please comment on this?Moazami
@dma_k, Java doesn't have real booleans actually. The size of boolean is 4bytes outside arrays and 1byte within boolean[]. Actually all primitives non double/long types are 4 bytes. The latter are 8 (the answer wrongly puts them as 4 too)Eran
@bestsss: To be more exact, minimal memory allocation depends on the platform and implementation of JVM. Also objects on heap are aligned, so after summing up all sizes one need to round up.Moazami
A
7

There is also the Memory Measurer tool (formerly at Google Code, now on GitHub), which is simple and published under the commercial-friendly Apache 2.0 license, as discussed in a similar question.

It, too, requires a command-line argument to the java interpreter if you want to measure memory byte consumption, but otherwise seems to work just fine, at least in the scenarios I have used it.

Acerose answered 5/9, 2013 at 20:13 Comment(0)
K
7

A possible year 2022 answer.

https://github.com/ehcache/sizeof

https://mvnrepository.com/artifact/org.ehcache/sizeof

https://mvnrepository.com/artifact/org.ehcache/sizeof/0.4.0

Version 0.4.0 has only a (compile) dependency on

https://mvnrepository.com/artifact/org.slf4j/slf4j-api

which is a good thing.

Sample code:

//import org.ehcache.sizeof.SizeOf;

SizeOf sizeOf = SizeOf.newInstance(); // (1)
long shallowSize = sizeOf.sizeOf(someObject); // (2)
long deepSize = sizeOf.deepSizeOf(someObject); // (3)
Karankaras answered 30/3, 2022 at 19:50 Comment(0)
E
6

The java.lang.instrument.Instrumentation class provides a nice way to get the size of a Java Object, but it requires you to define a premain and run your program with a java agent. This is very boring when you do not need any agent and then you have to provide a dummy Jar agent to your application.

So I got an alternative solution using the Unsafe class from the sun.misc. So, considering the objects heap alignment according to the processor architecture and calculating the maximum field offset, you can measure the size of a Java Object. In the example below I use an auxiliary class UtilUnsafe to get a reference to the sun.misc.Unsafe object.

private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
private static final int BYTE = 8;
private static final int WORD = NR_BITS/BYTE;
private static final int MIN_SIZE = 16; 

public static int sizeOf(Class src){
    //
    // Get the instance fields of src class
    // 
    List<Field> instanceFields = new LinkedList<Field>();
    do{
        if(src == Object.class) return MIN_SIZE;
        for (Field f : src.getDeclaredFields()) {
            if((f.getModifiers() & Modifier.STATIC) == 0){
                instanceFields.add(f);
            }
        }
        src = src.getSuperclass();
    }while(instanceFields.isEmpty());
    //
    // Get the field with the maximum offset
    //  
    long maxOffset = 0;
    for (Field f : instanceFields) {
        long offset = UtilUnsafe.UNSAFE.objectFieldOffset(f);
        if(offset > maxOffset) maxOffset = offset; 
    }
    return  (((int)maxOffset/WORD) + 1)*WORD; 
}
class UtilUnsafe {
    public static final sun.misc.Unsafe UNSAFE;

    static {
        Object theUnsafe = null;
        Exception exception = null;
        try {
            Class<?> uc = Class.forName("sun.misc.Unsafe");
            Field f = uc.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            theUnsafe = f.get(uc);
        } catch (Exception e) { exception = e; }
        UNSAFE = (sun.misc.Unsafe) theUnsafe;
        if (UNSAFE == null) throw new Error("Could not obtain access to sun.misc.Unsafe", exception);
    }
    private UtilUnsafe() { }
}
Extrasensory answered 14/5, 2012 at 16:37 Comment(7)
Interesting approach, but doesn't this suppose the object and its fields storage is not fragmented ?Stamps
Yes and I don't know any JVM implementation that makes such fragmentation.Extrasensory
I don't understand. Fragmentation is not an option :) Let's take the example of object C which is stored as a field of objects A and B. Doesn't it shift the whole thing in either A or B ?Stamps
Sorry, but I am not understanding either your point of view. According to my interpretation, in Java objects cannot be stored inside other objects, like happens with C structures or Value Types in .Net. So when you say: “object C which is stored as a field of objects A and B” that means that objects A and B have fields that store references (pointers) to the object C. Then the size of A and B are equals to the offset of that field plus the size of a reference (pointer) to the object C. And the size of a reference is the size of one word.Extrasensory
Oh, OK, we are talking about shallow size. My bad.Stamps
Unfortunately sun.misc.Unsafe is not allowed in the Google App Engine JVM! Project won't compile with the reference :(Faggoting
A hardcore Unsafe method is mentioned at: highlyscalable.wordpress.com/2012/02/02/… : he "just" reads an internal object length field.Strick
L
5

I was looking for a runtime calculation of an object size that met the following requirements:

  • Available at runtime with no need to include instrumentation.
  • Works with Java 9+ without access to Unsafe.
  • Is based on the Class only. Not a deep sizeOf that takes into consideration string lengths, array lengths, etc.

The following is based on the core code of the original java specialists article (https://www.javaspecialists.eu/archive/Issue078.html) and a few bits from the Unsafe version in another answer to this question.

I hope someone finds it useful.

public class JavaSize {

    private static final int NR_BITS = Integer.valueOf(System.getProperty("sun.arch.data.model"));
    private static final int BYTE = 8;
    private static final int WORD = NR_BITS / BYTE;
    private static final int HEADER_SIZE = 8;

    public static int sizeOf(Class<?> clazz) {
        int result = 0;

        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                if (!Modifier.isStatic(fields[i].getModifiers())) {
                    if (fields[i].getType().isPrimitive()) {
                        Class<?> primitiveClass = fields[i].getType();
                        if (primitiveClass == boolean.class || primitiveClass == byte.class) {
                            result += 1;
                        } else if (primitiveClass == short.class) {
                            result += 2;
                        } else if (primitiveClass == int.class || primitiveClass == float.class) {
                            result += 4;
                        } else if (primitiveClass == double.class || primitiveClass == long.class) {
                            result += 8;
                        }

                    } else {
                        // assume compressed references.
                        result += 4;
                    }
                }
            }

            clazz = clazz.getSuperclass();

            // round up to the nearest WORD length.
            if ((result % WORD) != 0) {
                result += WORD - (result % WORD);
            }
        }

        result += HEADER_SIZE;

        return result;
    }
 }
Lumpen answered 27/6, 2019 at 4:40 Comment(0)
E
4

Without having to mess with instrumentation and so on, and if you don't need to know the byte-exact size of an object, you could go with the following approach:

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

do your job here

System.gc();
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

This way you read the used memory before and after, and calling the GC just before getting the used memory you lower the "noise" almost to 0.

For a more reliable result you can run your job n times, and then divide the used memory by n, obtaining how much memory one run takes. Even more, you can run the whole thing more times and make an average.

Epsomite answered 3/4, 2015 at 12:9 Comment(4)
Doesn't System.gc() just notify that you want to GC? It is not guaranteed that the GC is called at all.Afterburning
@reallynice. This is not safe because you may never what GC does or affects memory between your lines. So "between" two freeMemory methods GC can free up more space that you do not consider thus your object will look smallerEstey
@MertSerimer "not safe" is on entire different level for me: at most this isn't so much accurate, as I also stated. Also, you can't drive the GC (as Raildex stated), but for this case too I suggested to insert this in a cycle. This is just a quick and dirty and approximate system which works if the result doesn't need to be very reliable, as stated.Epsomite
There are many problems with this but it does give you a good swag.Lionhearted
T
3

Here is a utility I made using some of the linked examples to handle 32-bit, 64-bit and 64-bit with compressed OOP. It uses sun.misc.Unsafe.

It uses Unsafe.addressSize() to get the size of a native pointer and Unsafe.arrayIndexScale( Object[].class ) for the size of a Java reference.

It uses the field offset of a known class to work out the base size of an object.

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.IdentityHashMap;
import java.util.Stack;
import sun.misc.Unsafe;

/** Usage: 
 * MemoryUtil.sizeOf( object )
 * MemoryUtil.deepSizeOf( object )
 * MemoryUtil.ADDRESS_MODE
 */
public class MemoryUtil
{
    private MemoryUtil()
    {
    }

    public static enum AddressMode
    {
        /** Unknown address mode. Size calculations may be unreliable. */
        UNKNOWN,
        /** 32-bit address mode using 32-bit references. */
        MEM_32BIT,
        /** 64-bit address mode using 64-bit references. */
        MEM_64BIT,
        /** 64-bit address mode using 32-bit compressed references. */
        MEM_64BIT_COMPRESSED_OOPS
    }

    /** The detected runtime address mode. */
    public static final AddressMode ADDRESS_MODE;

    private static final Unsafe UNSAFE;

    private static final long ADDRESS_SIZE; // The size in bytes of a native pointer: 4 for 32 bit, 8 for 64 bit
    private static final long REFERENCE_SIZE; // The size of a Java reference: 4 for 32 bit, 4 for 64 bit compressed oops, 8 for 64 bit
    private static final long OBJECT_BASE_SIZE; // The minimum size of an Object: 8 for 32 bit, 12 for 64 bit compressed oops, 16 for 64 bit
    private static final long OBJECT_ALIGNMENT = 8;

    /** Use the offset of a known field to determine the minimum size of an object. */
    private static final Object HELPER_OBJECT = new Object() { byte b; };


    static
    {
        try
        {
            // Use reflection to get a reference to the 'Unsafe' object.
            Field f = Unsafe.class.getDeclaredField( "theUnsafe" );
            f.setAccessible( true );
            UNSAFE = (Unsafe) f.get( null );

            OBJECT_BASE_SIZE = UNSAFE.objectFieldOffset( HELPER_OBJECT.getClass().getDeclaredField( "b" ) );

            ADDRESS_SIZE = UNSAFE.addressSize();
            REFERENCE_SIZE = UNSAFE.arrayIndexScale( Object[].class );

            if( ADDRESS_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_32BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 8 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT;
            }
            else if( ADDRESS_SIZE == 8 && REFERENCE_SIZE == 4 )
            {
                ADDRESS_MODE = AddressMode.MEM_64BIT_COMPRESSED_OOPS;
            }
            else
            {
                ADDRESS_MODE = AddressMode.UNKNOWN;
            }
        }
        catch( Exception e )
        {
            throw new Error( e );
        }
    }


    /** Return the size of the object excluding any referenced objects. */
    public static long shallowSizeOf( final Object object )
    {
        Class<?> objectClass = object.getClass();
        if( objectClass.isArray() )
        {
            // Array size is base offset + length * element size
            long size = UNSAFE.arrayBaseOffset( objectClass )
                    + UNSAFE.arrayIndexScale( objectClass ) * Array.getLength( object );
            return padSize( size );
        }
        else
        {
            // Object size is the largest field offset padded out to 8 bytes
            long size = OBJECT_BASE_SIZE;
            do
            {
                for( Field field : objectClass.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 )
                    {
                        long offset = UNSAFE.objectFieldOffset( field );
                        if( offset >= size )
                        {
                            size = offset + 1; // Field size is between 1 and PAD_SIZE bytes. Padding will round up to padding size.
                        }
                    }
                }
                objectClass = objectClass.getSuperclass();
            }
            while( objectClass != null );

            return padSize( size );
        }
    }


    private static final long padSize( final long size )
    {
        return (size + (OBJECT_ALIGNMENT - 1)) & ~(OBJECT_ALIGNMENT - 1);
    }


    /** Return the size of the object including any referenced objects. */
    public static long deepSizeOf( final Object object )
    {
        IdentityHashMap<Object,Object> visited = new IdentityHashMap<Object,Object>();
        Stack<Object> stack = new Stack<Object>();
        if( object != null ) stack.push( object );

        long size = 0;
        while( !stack.isEmpty() )
        {
            size += internalSizeOf( stack.pop(), stack, visited );
        }
        return size;
    }


    private static long internalSizeOf( final Object object, final Stack<Object> stack, final IdentityHashMap<Object,Object> visited )
    {
        // Scan for object references and add to stack
        Class<?> c = object.getClass();
        if( c.isArray() && !c.getComponentType().isPrimitive() )
        {
            // Add unseen array elements to stack
            for( int i = Array.getLength( object ) - 1; i >= 0; i-- )
            {
                Object val = Array.get( object, i );
                if( val != null && visited.put( val, val ) == null )
                {
                    stack.add( val );
                }
            }
        }
        else
        {
            // Add unseen object references to the stack
            for( ; c != null; c = c.getSuperclass() )
            {
                for( Field field : c.getDeclaredFields() )
                {
                    if( (field.getModifiers() & Modifier.STATIC) == 0 
                            && !field.getType().isPrimitive() )
                    {
                        field.setAccessible( true );
                        try
                        {
                            Object val = field.get( object );
                            if( val != null && visited.put( val, val ) == null )
                            {
                                stack.add( val );
                            }
                        }
                        catch( IllegalArgumentException e )
                        {
                            throw new RuntimeException( e );
                        }
                        catch( IllegalAccessException e )
                        {
                            throw new RuntimeException( e );
                        }
                    }
                }
            }
        }

        return shallowSizeOf( object );
    }
}
Torosian answered 26/6, 2014 at 5:36 Comment(5)
Did you tested this class with values ? I tried, but for me, incorrect values !!!.Chlorine
The values it gave me for a simple object were about correct, but off by a factor of 10 for a list containing 1mio objects. Still, very nice work!Nonentity
Interesting. I have tested it using JDK7u67, on Windows 7 x64 and Linux 2.6.16/x86_64, using each of 32bit/64bit/oop address modes. I have compared it to memory dumps analysed in Eclipse Memory Analyzer 1.3.x. What setup are you using? Do you have a specific example I could try?Torosian
Best choice I can do. I cant use Instrumentation because i don't start tomcat, ObjectSizeCalculator because not sure of VM type(HotSpot) and JOL bacouse spring beans. I use this and add second parameter for ignoring singletons viz AbstractRefreshableApplicationContext.getBeanFactory().getSingletonMutex() and refactor internalSizeOf code to ignore Class and EnumRaffaello
For comparing results use ObjectSizeCalculator (Compute whole server 1GB to 10s). JOL cause MemError (6GB not be enaught) and i don't get same results, probably because enums.Raffaello
O
3

Just use java visual VM.

It has everything you need to profile and debug memory problems.

It also has a OQL (Object Query Language) console which allows you to do many useful things, one of which being sizeof(o)

Orifice answered 23/3, 2018 at 11:53 Comment(0)
T
2

There isn't a method call, if that's what you're asking for. With a little research, I suppose you could write your own. A particular instance has a fixed sized derived from the number of references and primitive values plus instance bookkeeping data. You would simply walk the object graph. The less varied the row types, the easier.

If that's too slow or just more trouble than it's worth, there's always good old-fashioned row counting rule-of-thumbs.

Thermoelectricity answered 9/9, 2008 at 17:15 Comment(0)
O
2

I wrote a quick test once to estimate on the fly:

public class Test1 {

    // non-static nested
    class Nested { }

    // static nested
    static class StaticNested { }

    static long getFreeMemory () {
        // waits for free memory measurement to stabilize
        long init = Runtime.getRuntime().freeMemory(), init2;
        int count = 0;
        do {
            System.out.println("waiting..." + init);
            System.gc();
            try { Thread.sleep(250); } catch (Exception x) { }
            init2 = init;
            init = Runtime.getRuntime().freeMemory();
            if (init == init2) ++ count; else count = 0;
        } while (count < 5);
        System.out.println("ok..." + init);
        return init;
    }

    Test1 () throws InterruptedException {

        Object[] s = new Object[10000];
        Object[] n = new Object[10000];
        Object[] t = new Object[10000];

        long init = getFreeMemory();

        //for (int j = 0; j < 10000; ++ j)
        //    s[j] = new Separate();

        long afters = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            n[j] = new Nested();

        long aftersn = getFreeMemory();

        for (int j = 0; j < 10000; ++ j)
            t[j] = new StaticNested();

        long aftersnt = getFreeMemory();

        System.out.println("separate:      " + -(afters - init) + " each=" + -(afters - init) / 10000);
        System.out.println("nested:        " + -(aftersn - afters) + " each=" + -(aftersn - afters) / 10000);
        System.out.println("static nested: " + -(aftersnt - aftersn) + " each=" + -(aftersnt - aftersn) / 10000);

    }

    public static void main (String[] args) throws InterruptedException {
        new Test1();
    }

}

General concept is allocate objects and measure change in free heap space. The key being getFreeMemory(), which requests GC runs and waits for the reported free heap size to stabilize. The output of the above is:

nested:        160000 each=16
static nested: 160000 each=16

Which is what we expect, given alignment behavior and possible heap block header overhead.

The instrumentation method detailed in the accepted answer here the most accurate. The method I described is accurate but only under controlled conditions where no other threads are creating/discarding objects.

Oology answered 16/11, 2013 at 3:34 Comment(0)
C
1
long heapSizeBefore = Runtime.getRuntime().totalMemory();

// Code for object construction
...
long heapSizeAfter = Runtime.getRuntime().totalMemory();
long size = heapSizeAfter - heapSizeBefore;

size gives you the increase in memory usage of the jvm due to object creation and that typically is the size of the object.

Cambrian answered 7/5, 2014 at 7:23 Comment(1)
what if GC runs in the middle during // Code for object construction? Might now yield correct result all the time.Eggshell
T
1

My answer is based on the code supplied by Nick. That code measures total amount of bytes which are occupied by the serialized object. So this actually measures serialization stuff + plain object memory footprint (just serialize for example int and you will see that total amount of serialized bytes is not 4). So if you want to get raw byte number used exactly for your object - you need to modify that code a bit. Like so:

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectSizeCalculator {
    private Object getFirstObjectReference(Object o) {
        String objectType = o.getClass().getTypeName();

        if (objectType.substring(objectType.length()-2).equals("[]")) {
            try {
                if (objectType.equals("java.lang.Object[]"))
                    return ((Object[])o)[0];
                else if (objectType.equals("int[]"))
                    return ((int[])o)[0];
                else
                    throw new RuntimeException("Not Implemented !");
            } catch (IndexOutOfBoundsException e) {
                return null;
            }
        }

        return o;
    } 

    public int getObjectSizeInBytes(Object o) {
        final String STRING_JAVA_TYPE_NAME = "java.lang.String";

        if (o == null)
            return 0;

        String objectType = o.getClass().getTypeName();
        boolean isArray = objectType.substring(objectType.length()-2).equals("[]");

        Object objRef = getFirstObjectReference(o);
        if (objRef != null && !(objRef instanceof Serializable))
            throw new RuntimeException("Object must be serializable for measuring it's memory footprint using this method !");

        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(o);
            oos.close();
            byte[] bytes = baos.toByteArray();

            for (int i = bytes.length - 1, j = 0; i != 0; i--, j++) {
                if (objectType != STRING_JAVA_TYPE_NAME) {
                    if (bytes[i] == 112)
                        if (isArray)
                            return j - 4;
                        else
                            return j;
                } else {
                    if (bytes[i] == 0)
                        return j - 1;
                }
            }
        } catch (Exception e) {
            return -1;
        }

        return -1;
    }    

}

I've tested this solution with primitive types, String, and on some trivial classes. There may be not covered cases also.


UPDATE: Example modified to support memory footprint calculation of array objects.

Tades answered 16/10, 2014 at 15:2 Comment(0)
W
1

This answer is not related to Object size, but when you are using array to accommodate the objects; how much memory size it will allocate for the object.

So arrays, list, or map all those collection won't be going to store objects really (only at the time of primitives, real object memory size is needed), it will store only references for those objects.

Now the Used heap memory = sizeOfObj + sizeOfRef (* 4 bytes) in collection

  • (4/8 bytes) depends on (32/64 bit) OS

PRIMITIVES

int   [] intArray    = new int   [1]; will require 4 bytes.
long  [] longArray   = new long  [1]; will require 8 bytes.

OBJECTS

Object[] objectArray = new Object[1]; will require 4 bytes. The object can be any user defined Object.
Long  [] longArray   = new Long  [1]; will require 4 bytes.

I mean to say all the object REFERENCE needs only 4 bytes of memory. It may be String reference OR Double object reference, But depends on object creation the memory needed will vary.

e.g) If i create object for the below class ReferenceMemoryTest then 4 + 4 + 4 = 12 bytes of memory will be created. The memory may differ when you are trying to initialize the references.

 class ReferenceMemoryTest {
    public String refStr;
    public Object refObj;
    public Double refDoub; 
}

So when are creating object/reference array, all its contents will be occupied with NULL references. And we know each reference requires 4 bytes.

And finally, memory allocation for the below code is 20 bytes.

ReferenceMemoryTest ref1 = new ReferenceMemoryTest(); ( 4(ref1) + 12 = 16 bytes) ReferenceMemoryTest ref2 = ref1; ( 4(ref2) + 16 = 20 bytes)

Willson answered 3/3, 2015 at 7:4 Comment(2)
How can a 4-byte integer and an object reference of unknown size fit into 4 bytes?Ritualism
@EJP I mean to say all the object REFERENCE needs only 4 bytes of memory. It may be String reference OR Double object reference, But depends on object creation the memory needed will vary.Willson
H
1

If your application has the Apache commons lang library as a dependency or is using the Spring framework then you can also use the SerializationUtils class to quickly find out the approximate byte size of any given object.

byte[] data = SerializationUtils.serialize(user);
System.out.println("Approximate object size in bytes " + data.length);
Hooknosed answered 23/2, 2022 at 2:32 Comment(1)
does the serialization adds overhead? It seems the serialized byte size depends on the length of variable namesDemented
B
1

By using Lucene library org.apache.lucene.util.RamUsageEstimator

        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>8.7.0</version>
        </dependency>

You'll be able to measure the memory size of an object by

System.out.println("Object took " 
    + RamUsageEstimator.sizeOfObject(yourObj) / 1024 / 1024 + "mb");
Bulger answered 6/9, 2023 at 5:1 Comment(0)
B
0

You could generate a heap dump (with jmap, for example) and then analyze the output to find object sizes. This is an offline solution, but you can examine shallow and deep sizes, etc.

Boutis answered 4/4, 2013 at 15:8 Comment(0)
T
0

Suppose I declare a class named Complex like:

public class Complex {

    private final long real;
    private final long imaginary;

    // omitted
}

In order to see how much memory is allocated to live instances of this class:

$ jmap -histo:live <pid> | grep Complex

 num     #instances         #bytes  class name (module)
-------------------------------------------------------
 327:             1             32  Complex
Thanet answered 28/3, 2019 at 17:58 Comment(0)
C
-5

For JSONObject the below code can help you.

`JSONObject.toString().getBytes("UTF-8").length`

returns size in bytes

I checked it with my JSONArray object by writing it to a file. It is giving object size.

Coumarone answered 16/12, 2017 at 18:31 Comment(1)
this would only work for objects that are mostly strings.Harrar
Z
-6

I doubt you want to do it programmatically unless you just want to do it once and store it for future use. It's a costly thing to do. There's no sizeof() operator in Java, and even if there was, it would only count the cost of the references to other objects and the size of the primitives.

One way you could do it is to serialize the thing to a File and look at the size of the file, like this:

Serializable myObject;
ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("obj.ser"));
oos.write (myObject);
oos.close ();

Of course, this assumes that each object is distinct and doesn't contain non-transient references to anything else.

Another strategy would be to take each object and examine its members by reflection and add up the sizes (boolean & byte = 1 byte, short & char = 2 bytes, etc.), working your way down the membership hierarchy. But that's tedious and expensive and ends up doing the same thing the serialization strategy would do.

Zoologist answered 9/9, 2008 at 17:11 Comment(3)
I'd serialize it to a byte[] using a ByteArrayOutputStream. It would be a lot faster than writing it out to a file.Greenock
@KorayTugay Determining the byte size of an object is already a costly operation. Writing each object to disk to determine the size, is just going to make it crawl...Trioecious
The serialized object format is entirely different to the object’s format in the heap memory. Most notably, a descriptor for the object’s class (and all of its serializable superclasses) is written to the stream. So writing a simple instance of java.lang.Integer produces around 80 bytes, where the heap representation usually is 32 (unlike the object stream representation, the heap representation depends on pointer sizes and object alignment). In contrast, a serialized null reference requires one byte instead of the four or eight bytes in the heap memory.Geneviegenevieve

© 2022 - 2024 — McMap. All rights reserved.