Lecture from: 20.12.2024 | Video: Videos ETHZ

Memory Management in Java

This section explores how Java manages memory, including concepts like memory addresses, stack and heap memory, and the garbage collector. Understanding these concepts is crucial for writing efficient and robust Java programs.

Memory and Addresses

  • Bytes and Addresses: Every byte in memory has a unique address. A byte is the smallest unit of memory that can be addressed, and is typically 8 bits in size.

  • Words: A word is a group of bytes (typically 4 bytes or 32 bits). Word addresses are often used to represent memory locations, as they align with the underlying hardware architecture and allow faster access to data.

  • Hexadecimal Notation: Memory addresses are often represented in hexadecimal notation (base-16), using the digits 0-9 and A-F. This compact representation makes addresses easier to read and manage. They are frequently displayed using 4 digits, as seen in the image. Each word has its unique address.

Memory Areas

Java divides memory into three main areas:

  1. Static Data: This area stores constant values (like string literals or the value of final variables) as well as information about classes (e.g. class definitions, method bytecode). This information is available throughout the entire program execution. The space for these data is allocated during the program’s initialization and loading.

  2. Heap: The heap is where objects (instances of classes) are stored. The heap is dynamically managed, and grows and shrinks according to how many objects are currently in use. Object creation, which includes dynamic memory allocation for objects from the heap, and object access are discussed in more detail in the following slides.

  3. Stack: The stack is used for method calls and local variables. Each time a method is called, a new stack frame is created on the stack, and removed when the method returns. The stack grows and shrinks as methods are called and return, and its maximum size is limited. Exceeding this limit leads to a StackOverflowError.

Stack Frames

A stack frame is a block of memory on the stack allocated for each method call. It stores information related to that specific method invocation.

  • Contents of a Stack Frame:
    • Return Address: The address of the instruction to execute after the method returns. This enables proper resumption of program execution once the called method completes its operations.
    • Parameter Values: The values of the arguments passed to the method. These values are copied into the stack frame, isolating the method’s data from the caller’s data.
    • Local Variables: Variables declared within the method. These variables exist only during the method’s execution and are deallocated when the method finishes.

Primitive Types vs. Reference Types

  • Primitive Types (int, double, etc.): Stored directly in the stack (within a stack frame for local variables, or as part of an object on the heap for instance variables). The actual value is stored at that location in memory.

  • Reference Types (objects): Only the address of the object is stored. The object itself resides on the heap. Attributes (instance variables) of the object are also located on the heap, either directly (for primitive type attributes) or indirectly (with their addresses stored for reference type attributes).

Key point: Addresses can be stored on either the stack or the heap, but they always point to objects on the heap.

Local Reference Variables (with Pointers and Addresses)

Here’s how local reference variables work, illustrated with pointers and memory addresses:

This shows a conceptual view using arrows (pointers) to represent references. The local variables r and s point to objects in the heap, which contain their attributes. There is also an object on the stack named Max. This visualization makes the pointer analogy concrete.

This provides the same information but using actual memory addresses.

Key Point: The stack stores the variable r1 which holds the address of the actual Rational object on the heap (at address 1000). The heap stores the content of this Rational object (attributes num and den). This is a crucial distinction in Java’s memory model, as it determines how variables are accessed and passed around.

Step-by-Step Example

Shows a step-by-step execution of a program involving Rational objects, illustrating how stack frames are created and destroyed during method calls. Trace through the code and the image to see how memory is managed on the stack and the heap, with intermediate results illustrating the process. I suggest watching the lecture to see the animation…

Visualization: Pointers vs. Addresses

While references can be visualized as pointers (arrows), they are actually just numbers (memory addresses).

Primitive Types vs. Reference Types II (Passing as Parameters)

  • Primitive Types (Value Semantics): When passed as method parameters, a copy of the primitive value is created in the called method’s stack frame. Changes to the parameter inside the method do not affect the original value outside the method.

  • Reference Types (Reference Semantics): When passed as parameters, a copy of the object’s address is made and stored on the stack frame. Therefore, both the original reference and the parameter now point to the same object on the heap. Modifying the object through the parameter does affect the original object because both the original variable and the copied address in the parameter point to the same object. Reassigning the parameter reference variable within the method, however, does not affect the original variable.

Releasing Memory: Stack vs. Heap

  • Stack: Memory occupied by stack frames is automatically released when the corresponding method returns. This is managed by the JVM without needing any explicit intervention from your code.
  • Heap: Memory on the heap, used for storing objects, is managed by the garbage collector. The garbage collector reclaims memory occupied by objects that are no longer reachable (no variables are referring to them). This happens automatically at various points in time during program execution.

The Garbage Collector

The garbage collector is a crucial component of the Java runtime environment. It automatically manages memory on the heap by reclaiming memory occupied by unreachable objects. The internal functioning of a garbage collector is very complex.

Understanding the garbage collector is important, but internal details of different garbage collection algorithms are beyond the scope of introductory programming.

This was the last EProg lecture. We continued with some discussions about the exams and then continued with a quiz…

Hope you found these summaries useful. If you find errors or want to add something let me know :D