Stack & Heap Memory
- Memory Allocation: Stack and Heap
- Popcorn Hack: literal vs input
- Popcorn Hack: passing values and mutating shared objects
Memory Allocation: Stack and Heap
In Java, memory allocation for variables occurs in two main areas: the stack and the heap.
Stack Memory
Stack memory is a region of memory that stores temporary variables created by each function (including the main function). It is managed by the execution stack and follows a last-in-first-out (LIFO) order.
- Stores primitive data types and references to objects.
- Memory is allocated in a last-in-first-out (LIFO) manner.
- Each thread has its own stack; objects referenced from it may still be shared across threads.
Example:
int number = 100; // Stored in the stack
Stack Variables Tips
College Board often asks questions about stack usage.
- Local primitive variables hold values; primitive fields can also be stored inside heap objects.
- A reference variable holds a reference to an object, not the object itself.
- Java always passes arguments by value: a method receives a copy of a primitive value or a reference value.
- Reassigning a parameter does not reassign the caller’s variable.
- Mutating an object through a copied reference can affect the caller’s object because both references point to the same object. This is not pass-by-reference.
Heap Memory
Heap memory is a region of memory used for dynamic memory allocation. It is managed by Java’s memory management system.
- Used for storing objects and arrays.
- Shared among all threads, requiring synchronization for thread safety.
- Managed by the garbage collector, which can reclaim objects that are no longer reachable from GC roots.
Example:
// Long form showing new
String message = new String("Hello");
// A string literal refers to an interned String
String message = "Hello";
Heap Variables Tips
- An object remains reachable when there is a reference path from a GC root, such as a live thread or static field.
- Reference variables can be local variables or fields inside other objects.
- Heap objects are accessible only through references; shared mutable objects may need synchronization.
- Unreachable objects are eligible for garbage collection, but reclamation is not guaranteed to happen immediately.
Popcorn Hack: literal vs input
A value that is directly in code is called a literal. Often developers will say this value is hard coded value.
- Literal: In source code representation of a fixed value, e.g. 17. A hard coded number.
- String Literal: In sourced code set of letters within quotes, e.g. “blue”, A hard coded string.
Q1: Define some literal data. Q2: Obtain that data from input versus hard coded.
// Hard code literal values
int literalAge = 17;
String literalFavoriteColor = "blue";
// Input your age
Scanner scanObj = new Scanner(System.in); // Create a Scanner object
System.out.println("Enter age");
int inputAge = scanObj.nextInt(); // Read user input
System.out.println("My Age is: " + inputAge); // Output user input
Popcorn Hack: passing values and mutating shared objects
For College Articulation in Data Structures and the College Board AP Exam, distinguish copying a reference value from copying or mutating an object. Java always passes by value.
- If you pass primitives to a method they WILL NOT change the callers value.
- If you wrap the primitive in a refrence type, in the example below using a class, then you can change the original.
Q1: Describe approache difference between IntByValue and IntByReference. Q2: Try to make a changeInt method that change would persist after it is called. Be careful, this will require a change in approach.
public class IntByValue {
public static void changeInt(int n) {
System.out.println("In changeInt method");
System.out.println("\tBefore n += 10: n = " + n); // prints 5
n = n += 10;
System.out.println("\tAfter n += 10: n = " + n); // prints 10
}
public static void main(String[] args) {
int n = 5;
System.out.println("Main method before changeInt(n): n = " + n); // prints 5
changeInt(n);
System.out.println("Main method after changeInt(n): n = " + n); // still prints 5
}
}
IntByValue.main(null);
public class IntByReference {
private int value;
public IntByReference(Integer value) {
this.value = value;
}
public String toString() {
return (String.format("%d", this.value));
}
public void swapToLowHighOrder(IntByReference i) {
if (this.value > i.value) {
int tmp = this.value;
this.value = i.value;
i.value = tmp;
}
}
public static void swapper(int n0, int n1) {
IntByReference a = new IntByReference(n0);
IntByReference b = new IntByReference(n1);
System.out.println("Before: " + a + " " + b);
a.swapToLowHighOrder(b); // conditionally build swap method to change values of a, b
System.out.println("After: " + a + " " + b);
System.out.println();
}
public static void main(String[] ags) {
IntByReference.swapper(21, 16);
IntByReference.swapper(16, 21);
IntByReference.swapper(16, -1);
}
}
IntByReference.main(null);