13

What happens in the memory when a class instantiates the following object?

public class SomeObject{

    private String strSomeProperty;

    public SomeObject(String strSomeProperty){
        this.strSomeProperty = strSomeProperty;
    }
    public void setSomeProperty(String strSomeProperty){
        this.strSomeProperty = strSomeProperty;
    }
    public String getSomeProperty(){
        return this.strSomeProperty;
    }
}

In class SomeClass1:

SomeObject so1 = new SomeObject("some property value");

In class SomeClass2:

SomeObject so2 = new SomeObject("another property value");

How is memory allocated to the newly instantiated object and its properties?

trincot
  • 317,000
  • 35
  • 244
  • 286
Sajal Dutta
  • 18,272
  • 11
  • 52
  • 74

3 Answers3

12

Let's step through it:

SomeObject so1 = new SomeObject("some property value");

... is actually more complicated than it looks, because you're creating a new String. It might be easier to think of as:

String tmp = new String("some property value");
SomeObject so1 = new SomeObject(tmp);
// Not that you would normally write it in this way.

(To be absolutely accurate - these are not really equivalent. In the original the 'new String' is created at compile time and is part of the .class image. You can think of this as a performance hack.)

So, first the JVM allocates space for the String. You typically don't know or care about the internals of the String implementation, so just take it on trust that a chunk of memory is being used to represent "some property value". Also, you have some memory temporarily allocated containing a reference to the String. In the second form, it's explicitly called tmp; in your original form Java handles it without naming it.

Next the JVM allocates space for a new SomeObject. That's a bit of space for Java's internal bookkeeping, and space for each of the object's fields. In this case, there's just one field, strSomeProperty.

Bear in mind that strSomeProperty is just a reference to a String. For now, it'll be initialised to null.

Next, the constructor is executed.

this.strSomeProperty = strSomeProperty;

All this does is copy the reference to the String, into your strSomeProperty field.

Finally, space is allocated for the object reference so1. This is set with a reference to the SomeObject.

so2 works in exactly the same way.

slim
  • 40,215
  • 13
  • 94
  • 127
  • 3
    No, it's not more complicated than it looks. "a" and new String("a") are not equivalent expressions. String literals are interned by the compiler. They don't incur additional heap allocations when they are used. – bendin Nov 26 '08 at 15:24
  • Touche :) However I think interning is conceptually even more complicated than what I decribed. I guess the appropriate answer depends on the intent of the question. – slim Nov 26 '08 at 15:32
  • 3
    Interning may conceptually more complicated, but it has the advantage of being correct. – Tom Hawtin - tackline Nov 26 '08 at 20:18
  • 3
    I'll draw the analogy with chemistry. In British schools, 16 year olds are taught Bohr's model of the atom. It is useful in many cases, and it is simpler than the truth, which is taught at higher levels. I will edit the text to clarify though. – slim Nov 27 '08 at 11:53
  • Unsuccessful edit. He is not creating a new String. Your second version is not equivalent to the first. – user207421 Apr 11 '17 at 01:24
7

Determining Memory Usage in Java by Dr. Heinz M. Kabutz gives a precise answer, plus a program to calculate the memory usage. The relevant part:

  1. The class takes up at least 8 bytes. So, if you say new Object(); you will allocate 8 bytes on the heap.
  2. Each data member takes up 4 bytes, except for long and double which take up 8 bytes. Even if the data member is a byte, it will still take up 4 bytes! In addition, the amount of memory used is increased in 8 byte blocks. So, if you have a class that contains one byte it will take up 8 bytes for the class and 8 bytes for the data, totalling 16 bytes (groan!).
  3. Arrays are a bit more clever. Primitives get packed in arrays, so if you have an array of bytes they will each take up one byte (wow!). The memory usage of course still goes up in 8 byte blocks.

As people have pointed out in the comments, Strings are a special case, because they can be interned. You can reason about the space they take up in the same way, but keep in mind that what looks like multiple copies of the same String may actually point to the same reference.

Craig P. Motlin
  • 26,452
  • 17
  • 99
  • 126
  • 1
    Note that this is 7 years old, and based on empirical evidence using a particular JVM on a particular operating system at that time (the article says as much). Unless you know for sure what JVM you're going to be running on, you can't be this precise. – slim Nov 26 '08 at 17:24
  • Good point. I wouldn't be surprised if some things that used to take 4 bytes take 8 on a 64 bit platform. However, the program determines the size of an object empirically. Running it on the target VM will give a precise answer. – Craig P. Motlin Nov 26 '08 at 17:37
  • It's also possible that newer VMs have a more efficient approach to storing booleans, shorts etc., or that the behaviour varies between platforms (JME could be optimised for memory), or that the JVM changes strategy as it approaches heap limits. – slim Nov 27 '08 at 11:52
  • How are arrays abit more clever? – Pacerier Feb 21 '12 at 23:53
  • @CraigP.Motlin Do you mean that storing 3 integers will take 16 bytes? – Pacerier Feb 23 '12 at 17:50
  • @Pacerier Yes, plus the array that they're in has the overhead of a normal object, and a length. – Craig P. Motlin Feb 25 '12 at 02:13
  • Why a class takes 8 bytes when created, Can you please explain it? – Akash5288 Jan 12 '14 at 11:45
  • Arrays are objects, and only a reference is stored in the containing object. How the elements are packed is therefore irrelevant to the size of the containing object. – user207421 Apr 11 '17 at 01:26
  • Regardless of the type you're instantiating, does the "size" of the object get written somewhere in the class file so you allocate that much of amount instead of re-calculating it each time? – stdout Jun 29 '18 at 13:10
3

Points to remember:

  1. When a method is called, a frame is created on the top of stack.
  2. Once a method has completed execution, flow of control returns to the calling method and its corresponding stack frame is flushed.
  3. Local variables are created in the stack.
  4. Instance variables are created in the heap & are part of the object they belong to.
  5. Reference variables are created in the stack.

Ref: http://www.javatutorialhub.com/java-stack-heap.html

Mihai Iorga
  • 39,330
  • 16
  • 106
  • 107
Shishir
  • 39
  • 1
  • *Local* reference variables are created in the stack. Reference *instance members* are created in the containing object, in the heap. None of this answers the question. – user207421 Apr 11 '17 at 01:27