Java learning pathSection 3

Runtime Data Areas

Map the JVM's shared and per-thread memory areas, trace a small program across them, and separate heap limits from the full process memory budget.

1

The JVM organizes memory supplied by the operating system

When java Hello launches an application, the operating system starts a process and the JVM obtains memory through operating-system facilities. The JVM creates logical runtime areas; it does not manufacture RAM or automatically claim all installed memory.

Memory requirements depend on the application, Java version, JVM implementation, collector, number of threads, and configuration. Some regions are established at startup; others grow as classes load, threads begin, or the application allocates more objects.

Reserved virtual address space, committed memory, and resident physical pages are different measurements. A maximum heap reservation is not proof that all of that memory is currently occupied by live Java objects or resident in RAM.

2

Shared areas versus each thread's execution state

The heap and logical method area are shared by JVM threads. Each thread has its own Java stack and program-counter state; a JVM may also use native method stacks. These separate responsibilities let multiple threads execute different methods while referring to the same objects and class definitions.

A reference kept in a private local-variable slot can still point to a shared heap object. Private stack storage does not make the referenced object thread-safe. Two threads may hold different references to the very same mutable object.

The five-area model describes JVM responsibilities, not necessarily five physically separate allocations. For example, a concrete runtime can use one underlying native thread stack for both Java and native execution.

A JVM process with shared heap and method area above two separate thread panels, each containing a Java stack, PC state, and native-call support.
Objects and class metadata are shared resources; stacks and instruction state belong to individual threads.
3

Method area: the logical home of class information

The JVM specification defines a shared method area for per-class structures, including runtime constant pools and field and method information. Loading Student makes its definition available; creating a thousand Student instances does not require a thousand copies of that definition.

Modern HotSpot uses native-memory Metaspace for much of this class metadata. The method area is a specification concept, whereas Metaspace is an implementation choice. Do not treat the two terms as universally interchangeable across all JVMs.

Class metadata describes fields, constructors, superclass relationships, interfaces, and methods. The heap stores the actual Student instances and java.lang.Class mirrors. In HotSpot, static field values are associated with those heap-resident class mirrors, rather than all static values physically residing in Metaspace.

4

Heap: objects, arrays, and reachability

The heap is the shared runtime area from which memory for class instances and arrays is allocated. In Student s = new Student(), the object belongs to the heap model, while a method-local s is a reference value held in the current frame.

The garbage collector reclaims objects that are no longer reachable through its root set. Roots include active execution references, live class-associated references, and JNI references. Merely assigning s = null does not make an object collectible if another reference still reaches it.

Heap size is not the same as live data size: the heap also needs free capacity for allocations and collection work. Collectors may move objects, so a Java reference should not be understood as an address that application code can safely manipulate.

The runtime model describes objects as heap allocations. Optimizing compilers may eliminate a non-escaping allocation or replace its fields with scalar values; this optimization does not turn the simplified rule 'all references are on the stack' into a correct generalization. References can also be fields or array elements in the heap.

Example
Student first = new Student();
Student second = first;
first = null;
// The object is still reachable through second.
second = null;
// If no other roots reach it, it is now eligible for GC.
// Eligibility does not mean immediate reclamation.
5

Java stacks: one sequence of calls per thread

Each JVM thread has a private Java stack containing frames for active method invocations. A frame contains local-variable slots and an operand stack, along with information supporting dynamic linking and return to the caller.

When main calls display and display calls calculate, calculate is the active frame. On normal return its frame is discarded and display resumes; display then returns to main. Exception propagation can instead unwind several frames until a matching handler is found.

Primitive local values and local reference values belong to a method's logical frame. The object reached by a reference is not embedded in that frame merely because the variable is local. Frame removal also does not destroy a heap object that remains reachable elsewhere.

Excessive call depth can exhaust the permitted stack and produce StackOverflowError. Allocating a new thread or expanding stacks can also fail from memory pressure, so stack-related failures are not all identical.

6

Program counter: each thread's current bytecode position

For a non-native method, a thread's program counter identifies the JVM instruction currently being executed. Branches, method calls, and returns change the flow; the PC does not simply count upward through the whole application.

Two threads can execute the same method at different bytecode positions. Their independent PC state lets the runtime track each execution separately even when they share the method definition and heap objects.

The JVM specification leaves the PC value undefined while a native method is executing. The JVM PC is a logical execution concept, not a claim that every Java thread permanently owns a dedicated physical CPU register.

7

Native method stacks and JNI support

Native methods execute code outside the Java bytecode instruction set, commonly C or C++ machine code. The JVM may use conventional native stacks to support these calls, their arguments, local state, and returns.

JNI defines a bridge for native code to interact with Java methods, objects, and exceptions. The Java call state must remain coherent while native code runs and then returns. Native references can also affect garbage-collector reachability.

The physical stack organization is implementation-dependent; it is misleading to require a separately allocated native stack beside every Java stack. Native allocations are also outside the ordinary Java heap limit and may require explicit cleanup.

8

Trace a Student across the memory areas

In the following example, loading Hello and Student makes their class information available to the runtime. Invoking main establishes a frame with local slots, and new Student creates an instance in the heap model.

The primitive x has the value 10 in main's local state. The local s holds a reference to the Student instance. Its name field points to a String object in the heap; the text of the string is not class metadata just because the literal occurs in a class file.

While main executes Java instructions, the thread's PC tracks the current bytecode position. Printing the name uses Java library code and eventually platform facilities, potentially involving native execution. These are collaborating memory areas, not successive storage bins through which the object travels.

Main frame with x equals 10 and reference s pointing to a heap Student object, whose name points to a String; separate Metaspace holds Hello and Student metadata.
Separate the variable, the instance, and the class definition. A reference connects them without merging their lifetimes.
Example
class Student {
    String name = "John";
}

public class Hello {
    public static void main(String[] args) {
        int x = 10;
        Student s = new Student();
        System.out.println(s.name + " " + x);
    }
}
9

Configure a process budget, not just a heap

The source's example java -Xms512m -Xmx2g -Xss1m Hello sets an initial heap of 512 MiB, a maximum heap of 2 GiB, and a requested thread stack size of 1 MiB. Actual defaults, limits, commitment, and accepted values depend on the VM and platform.

-Xmx does not cap the entire process. Leave room for Metaspace, JIT-compiled code, thread stacks, direct buffers, native libraries, collector structures, and other runtime overhead. In a container, consider its memory limit rather than only the host's installed RAM.

A growing heap is not automatically a leak: the JVM can expand committed heap capacity within its configured maximum. Diagnose whether live data after collection keeps growing, which region is under pressure, and whether the process is being killed externally before changing a size flag.

Configure a process budget, not just a heap
Region or resourceTypical controlImportant boundary
Java heap-Xms and -XmxExcludes native and other non-heap allocations
Thread stacks-XssMany threads multiply stack-related memory costs
HotSpot Metaspace-XX:MaxMetaspaceSizeUses native memory; not charged to -Xmx
Whole processOS / container budget and measurementsMust accommodate all regions and overhead