views:

2191

answers:

7

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?

+2  A: 

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

Mendelt
+1  A: 

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

Burkhard
+7  A: 

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).

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

Jon Skeet
+17  A: 

According to JavaWorld

A plain Object takes 8 bytes;

So 'no' is the answer;

Note: In addition, JDK 1.5 has added an Instrumentation interface, which includes a method named getObjectSize() method.

Mindprod summarizes the different sizes, which does not change between 32 and 64bits OS, except for object references. Some 64-bits JVM can compressed their object references in order to avoid the overhead when run on 32-bits platform.

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.


The JavaWorld article gives a little more detail about storage overhead depending on the container used:

For instance, Wrappers can be costly too compared to primitive type for attributes:

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.

VonC
Thanks Jon, those square brackets are tricky ;)
VonC
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!
JeeBee
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.
JeeBee
@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!
VonC
+1  A: 

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.

Matt Passell
A: 

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 at http://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/5163

Regards, Markus

kohlerm
A: 

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.

Neil Coffey