What is the memory consumption of an object in Java?
Asked Answered
I

12

246

Is the memory space consumed by one object with 100 attributes the same as that of 100 objects, with one attribute each?

How much memory is allocated for an object?
How much additional space is used when adding an attribute?

Impenitent answered 3/11, 2008 at 8:24 Comment(0)
D
201

Mindprod points out that this is not a straightforward question to answer:

A JVM is free to store data any way it pleases internally, big or little endian, with any amount of padding or overhead, though primitives must behave as if they had the official sizes.
For example, the JVM or native compiler might decide to store a boolean[] in 64-bit long chunks like a BitSet. It does not have to tell you, so long as the program gives the same answers.

  • It might allocate some temporary Objects on the stack.
  • It may optimize some variables or method calls totally out of existence replacing them with constants.
  • It might version methods or loops, i.e. compile two versions of a method, each optimized for a certain situation, then decide up front which one to call.

Then of course the hardware and OS have multilayer caches, on chip-cache, SRAM cache, DRAM cache, ordinary RAM working set and backing store on disk. Your data may be duplicated at every cache level. All this complexity means you can only very roughly predict RAM consumption.

Measurement methods

You can use Instrumentation.getObjectSize() to obtain an estimate of the storage consumed by an object.

To visualize the actual object layout, footprint, and references, you can use the JOL (Java Object Layout) tool.

Object headers and Object references

In a modern 64-bit JDK, an object has a 12-byte header, padded to a multiple of 8 bytes, so the minimum object size is 16 bytes. For 32-bit JVMs, the overhead is 8 bytes, padded to a multiple of 4 bytes. (From Dmitry Spikhalskiy's answer, Jayen's answer, and JavaWorld.)

Typically, references are 4 bytes on 32bit platforms or on 64bit platforms up to -Xmx32G; and 8 bytes above 32Gb (-Xmx32G). (See compressed object references.)

As a result, a 64-bit JVM would typically require 30-50% more heap space. (Should I use a 32- or a 64-bit JVM?, 2012, JDK 1.7)

Boxed types, arrays, and strings

Boxed wrappers have overhead compared to primitive types (from JavaWorld):

  • Integer: The 16-byte result is a little worse than I expected because an int value can fit into just 4 extra bytes. Using an Integer costs me a 300 percent memory overhead compared to when I can store the value as a primitive type

  • Long: 16 bytes also: Clearly, actual object size on the heap is subject to low-level memory alignment done by a particular JVM implementation for a particular CPU type. It looks like a Long is 8 bytes of Object overhead, plus 8 bytes more for the actual long value. In contrast, Integer had an unused 4-byte hole, most likely because the JVM I use forces object alignment on an 8-byte word boundary.

Other containers are costly too:

  • Multidimensional arrays: it offers another surprise.
    Developers commonly employ constructs like int[dim1][dim2] in numerical and scientific computing.

    In an int[dim1][dim2] array instance, every nested int[dim2] array is an Object in its own right. Each adds the usual 16-byte array overhead. When I don't need a triangular or ragged array, that represents pure overhead. The impact grows when array dimensions greatly differ.

    For example, a int[128][2] instance takes 3,600 bytes. Compared to the 1,040 bytes an int[256] instance uses (which has the same capacity), 3,600 bytes represent a 246 percent overhead. In the extreme case of byte[256][1], the overhead factor is almost 19! Compare that to the C/C++ situation in which the same syntax does not add any storage overhead.

  • String: a String's memory growth tracks its internal char array's growth. However, the String class adds another 24 bytes of overhead.

    For a nonempty String of size 10 characters or less, the added overhead cost relative to useful payload (2 bytes for each char plus 4 bytes for the length), ranges from 100 to 400 percent.

Alignment

Consider this example object:

class X {                      // 8 bytes for reference to the class definition
   int a;                      // 4 bytes
   byte b;                     // 1 byte
   Integer c = new Integer();  // 4 bytes for a reference
}

A naïve sum would suggest that an instance of X would use 17 bytes. However, due to alignment (also called padding), the JVM allocates the memory in multiples of 8 bytes, so instead of 17 bytes it would allocate 24 bytes.

Defame answered 3/11, 2008 at 8:42 Comment(8)
int[128][6]: 128 arrays of 6 ints - 768 ints in total, 3072 bytes of data + 2064 bytes Object overhead = 5166 bytes total. int[256]: 256 ints in total - therefore non-comparable. int[768]: 3072 bytes of data + 16 byes overhead - about 3/5th of the space of the 2D array - not quite 246% overhead!Lightfoot
Ah, the original article used int[128][2] not int[128][6] - wonder how that got changed. Also shows that extreme examples can tell a different story.Lightfoot
@Jeebee: I have fixed the typos. int[128][2] became int[128][6] because of a bug in the Javascript editor: the links are referenced with [aTest][x] and the editor assumed [128][2] to be an link address! It did "re-order" the indexes of those links, changing the [2] into [6]... tricky!Defame
The overhead is 16 bytes in 64bit JVM's.Teryl
@TimCooper No! The overhead (= new Object()) of Sun VM Java 1.6 64bit running on Win7 64 bit Intel is 12 bytes + 4 padding to next multiple of 8 makes 16 bytes. So if you have an object with one field int, it is still 16 bytes. (no padding)Eczema
@AlexWien: Some garbage-collection schemes may impose a minimum object size which is separate from padding. During garbage collection, once an object gets copied from an old location to a new one, the old location may not need to hold the data for the object any more, but it will need to hold a reference to the new location; it may also need to store a reference to the old location of the object wherein the first reference was discovered and the offset of that reference within the old object [since the old object may still contain references that haven't yet been processed].Toshikotoss
@AlexWien: Using memory at an object's old location to hold the garbage-collector's book-keeping information avoids the need to allocate other memory for that purpose, but may impose a minimum object size which is larger than would otherwise be required. I think at least one version of .NET garbage collector uses that approach; it would certainly be possible for some Java garbage collectors to do so as well.Toshikotoss
@Defame This answer is outdated because lots of people are using 64bit JVM's these days and your answer is effectively ignoring 64bit JVM's. It's good to say "well, it depends..." but it's also good to give some good practical advice - things that are true for 99% of JVM's out there such as "8 bytes for 32bit, 12 bytes + 8-byte alignment for 64 bit, plus pointers are 8 bytes above -Xmx32G".Teryl
A
38

It depends on the CPU architecture and JDK. For a modern JDK and 64-bit architecture, an object has 12-byte header and padding of 8 bytes - so the minimum object size is 16 bytes. You can use a tool called Java Object Layout to determine a size and get details about any entity's object layout and internal structure or guess this information by class reference. Example of output for Integer instance on my environment:

Running 64-bit HotSpot VM.
Using compressed oop with 3-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]

java.lang.Integer object internals:
 OFFSET  SIZE  TYPE DESCRIPTION                    VALUE
      0    12       (object header)                N/A
     12     4   int Integer.value                  N/A
Instance size: 16 bytes (estimated, the sample instance is not available)
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

For Integer, the instance size is 16 bytes: 4-bytes int is placed in place right after the 12-byte header. And it doesn't need any additional "padding", because 16 is a multiple of 8 (which is a RAM word size on 64-bits architecture) without remainder.

Code sample:

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.util.VMSupport;

public static void main(String[] args) {
    System.out.println(VMSupport.vmDetails());
    System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
}

If you use maven, to get JOL:

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.3.2</version>
</dependency>
Armipotent answered 26/8, 2015 at 10:43 Comment(0)
R
29

Each object has a certain overhead for its associated monitor and type information, as well as the fields themselves. Beyond that, fields can be laid out pretty much however the JVM sees fit (I believe) - but as shown in another answer, at least some JVMs will pack fairly tightly. Consider a class like this:

public class SingleByte
{
    private byte b;
}

vs

public class OneHundredBytes
{
    private byte b00, b01, ..., b99;
}

On a 32-bit JVM, I'd expect 100 instances of SingleByte to take 1200 bytes (8 bytes of overhead + 4 bytes for the field due to padding/alignment). I'd expect one instance of OneHundredBytes to take 108 bytes - the overhead, and then 100 bytes, packed. It can certainly vary by JVM though - one implementation may decide not to pack the fields in OneHundredBytes, leading to it taking 408 bytes (= 8 bytes overhead + 4 * 100 aligned/padded bytes). On a 64 bit JVM the overhead may well be bigger too (not sure).

EDIT: See the comment below; apparently HotSpot pads to 8 byte boundaries instead of 32, so each instance of SingleByte would take 16 bytes.

Either way, the "single large object" will be at least as efficient as multiple small objects - for simple cases like this.

Reahard answered 3/11, 2008 at 8:39 Comment(1)
Actually, one instance of SingleByte would take 16 bytes on a Sun JVM, that is 8 bytes overhead, 4 bytes for the field, and then 4 bytes for object padding, since the HotSpot compiler rounds everything to multiples of 8.Helfrich
C
8

The total used / free memory of a program can be obtained in the program via

java.lang.Runtime.getRuntime();

The runtime has several methods which relate to the memory. The following coding example demonstrates its usage.

 public class PerformanceTest {
     private static final long MEGABYTE = 1024L * 1024L;

     public static long bytesToMegabytes(long bytes) {
         return bytes / MEGABYTE;
     }

     public static void main(String[] args) {
         // I assume you will know how to create an object Person yourself...
         List <Person> list = new ArrayList <Person> ();
         for (int i = 0; i <= 100_000; i++) {
             list.add(new Person("Jim", "Knopf"));
         }

         // Get the Java runtime
         Runtime runtime = Runtime.getRuntime();

         // Run the garbage collector
         runtime.gc();

         // Calculate the used memory
         long memory = runtime.totalMemory() - runtime.freeMemory();
         System.out.println("Used memory is bytes: " + memory);
         System.out.println("Used memory is megabytes: " + bytesToMegabytes(memory));
     }
 }
Christiansen answered 24/1, 2013 at 12:55 Comment(0)
C
8

It appears that every object has an overhead of 16 bytes on 32-bit systems (and 24-byte on 64-bit systems).

http://algs4.cs.princeton.edu/14analysis/ is a good source of information. One example among many good ones is the following.

enter image description here

https://www.yumpu.com/en/memory-efficient-java-tutorial is also very informative, for example:

enter image description here

Creepy answered 5/5, 2015 at 21:49 Comment(3)
"It appears that every object has an overhead of 16 bytes on 32-bit systems (and 24-byte on 64-bit systems)." It's not correct, at least for current JDKs. Take a look at my answer for Integer example. Overhead of object is at least 12 bytes for header for 64-bit system and modern JDK. Can be more because of padding, depends on actual layout of fields in object.Armipotent
The second link to the memory efficient Java tutorial seems to be dead–I get "Forbidden".Paulettepauley
@Paulettepauley in case your are still interested in the dead-link pdf file: you can download it at: yumpu.com/en/memory-efficient-java-tutorialAbsorptance
P
6

Is the memory space consumed by one object with 100 attributes the same as that of 100 objects, with one attribute each?

No.

How much memory is allocated for an object?

  • The overhead is 8 bytes on 32-bit, 12 bytes on 64-bit; and then rounded up to a multiple of 4 bytes (32-bit) or 8 bytes (64-bit).

How much additional space is used when adding an attribute?

  • Attributes range from 1 byte (byte) to 8 bytes (long/double), but references are either 4 bytes or 8 bytes depending not on whether it's 32bit or 64bit, but rather whether -Xmx is < 32Gb or >= 32Gb: typical 64-bit JVM's have an optimisation called "-UseCompressedOops" which compress references to 4 bytes if the heap is below 32Gb.
Penholder answered 15/2, 2016 at 11:16 Comment(2)
a char is 16bit, not 8bit.Tantivy
right you are. someone seems to have edited my original answerPenholder
D
5

No, registering an object takes a bit of memory too. 100 objects with 1 attribute will take up more memory.

Dionysiac answered 3/11, 2008 at 8:26 Comment(0)
N
5

The question will be a very broad one.

It depends on the class variable or you may call as states memory usage in java.

It also has some additional memory requirement for headers and referencing.

The heap memory used by a Java object includes

  • memory for primitive fields, according to their size (see below for Sizes of primitive types);

  • memory for reference fields (4 bytes each);

  • an object header, consisting of a few bytes of "housekeeping" information;

Objects in java also requires some "housekeeping" information, such as recording an object's class, ID and status flags such as whether the object is currently reachable, currently synchronization-locked etc.

Java object header size varies on 32 and 64 bit jvm.

Although these are the main memory consumers jvm also requires additional fields sometimes like for alignment of the code e.t.c.

Sizes of primitive types

boolean & byte -- 1

char & short -- 2

int & float -- 4

long & double -- 8

Noli answered 18/5, 2013 at 14:23 Comment(1)
Readers may also find this paper very illuminating: cs.virginia.edu/kim/publicity/pldi09tutorials/…Mireyamiriam
S
3

I've gotten very good results from the java.lang.instrument.Instrumentation approach mentioned in another answer. For good examples of its use, see the entry, Instrumentation Memory Counter from the JavaSpecialists' Newsletter and the java.sizeOf library on SourceForge.

Snow answered 4/11, 2008 at 1:27 Comment(0)
T
3

In case it's useful to anyone, you can download from my web site a small Java agent for querying the memory usage of an object. It'll let you query "deep" memory usage as well.

Team answered 7/4, 2009 at 17:10 Comment(1)
This worked great for getting a rough estimate of how much memory a (String, Integer) Guava Cache uses, per-element. Thanks!Concertino
D
1

no, 100 small objects needs more information (memory) than one big.

Defiant answered 3/11, 2008 at 8:27 Comment(0)
M
0

The rules about how much memory is consumed depend on the JVM implementation and the CPU architecture (32 bit versus 64 bit for example).

For the detailed rules for the SUN JVM check my old blog

Regards, Markus

Magnesite answered 13/11, 2008 at 8:18 Comment(3)
I am pretty sure Sun Java 1.6 64bit, need 12 bytes for a plain object + 4 padding = 16; an Object + one integer field = 12 + 4 = 16Eczema
Did you shutdown your blog?Klement
Not really, Not sure the SAP blogs somehow moved. Most of it can be found here kohlerm.blogspot.comMagnesite

© 2022 - 2024 — McMap. All rights reserved.