Stack and heap
A running program uses two main memory areas:
| Area | Stores | Lifetime |
|---|---|---|
| Stack | Local variables and method parameters, including local reference variables. Each method call gets its own frame | Freed automatically when the method returns |
| Heap | Objects (everything created with new), including their attributes (instance variables) | Lives while it can be reached; once unreachable, the garbage collector may reclaim it |
Student s = new Student("Nimal", 80);The reference variable s sits on the stack. The Student object itself sits on the heap. s holds the address of the object.
How the stack works
The stack works like a pile of plates. When a method is called, a new frame is put on top of the stack. It holds the method's parameters and local variables. When the method returns, its frame is taken off, and all of its local variables disappear at once. The method that is running now is always the one at the top.
public static void main(String[] args) {
int x = 5;
Student s = new Student("Nimal", 80);
printTwice(x);
}
static void printTwice(int n) {
int result = n * 2;
System.out.println(result);
}- While
mainruns, its frame holdsargs,x(the value 5) ands(a reference). The Student object is on the heap. - When
printTwice(x)is called, a new frame goes on top, holdingn(a copy of 5) andresult. - When
printTwicereturns, its frame is removed.nandresultare gone, butmain's frame and the Student object are untouched.
If a method keeps calling itself and never stops, frames pile up until the stack is full, and Java throws a StackOverflowError.
Primitive variables and reference variables
Primitive variable (int, double, boolean, ...) | Reference variable (Student, String, arrays, ...) |
|---|---|
| Holds the value itself | Holds the address of an object on the heap |
int b = a; copies the value; the two are independent | Student t = s; copies the address; both refer to the same object |
Cannot be null | Can be null (refers to no object) |
Passing objects to methods
Java always passes a copy of the argument. For a primitive that is a copy of the value, so the method cannot change the caller's variable. For an object it is a copy of the reference, so the method can change the object that both references point to:
static void addBonus(Student st) { st.marks = st.marks + 5; }
Student s = new Student("Nimal", 80);
addBonus(s);
System.out.println(s.marks); // 85: the same object was changedDynamic memory allocation
Dynamic allocation means memory is requested while the program runs, with a size that may not be known beforehand.
- In Java,
newallocates an object (or array) on the heap. Memory is released automatically. - In C++,
newallocates and the programmer must calldeleteto free the memory. Forgettingdeletecauses a memory leak; using memory afterdeletecauses a dangling pointer error.
int[] marks = new int[n]; // size decided at run time
Student[] list = new Student[30]; // 30 references, all null
list[0] = new Student("Nimal", 80); // objects created on demandnull means a reference points to no object. Calling a method on null throws a NullPointerException.
Memory problems in C++, and how Java avoids them
| Problem | What happens in C++ | Java |
|---|---|---|
| Memory leak | Memory from new is never released with delete. The program uses more and more memory | The garbage collector frees unreachable objects |
| Dangling pointer | Memory is used after delete. The program may crash, or read rubbish | There is no delete, so this cannot happen |
| Double delete | The same memory is freed twice, which corrupts memory | Cannot happen |
Java trades a little control (you cannot choose when memory is freed) for a lot of safety.
Remember
- The stack holds method frames with local variables; it is cleaned up automatically when each method returns.
- The heap holds objects; a reference variable holds the object's address.
- Copying a reference does not copy the object, and a method that receives a reference can change the object.