Skip to content

Latest commit

 

History

History
447 lines (296 loc) · 9.14 KB

File metadata and controls

447 lines (296 loc) · 9.14 KB

Process, Threads, and Their Memory Model

1. What Is a Process?

A process is an independent program in execution, created and managed by the operating system. When you run a Java program, the OS:

  1. Loads the JVM executable
  2. Creates a new process
  3. Allocates isolated memory regions (stack, heap, code, data)
  4. Starts the program with its own JVM instance

Key Characteristics:

  • Each process has its own address space
  • One crashed process does not affect others
  • No memory is shared unless explicitly done using IPC
  • Every Java application you run → 1 dedicated OS process

2. Complete Java Execution Workflow

Running a Java file involves several components:

javac  → compile source to bytecode (.class)
java   → launch JVM process → load class → interpret/JIT → execute

Step-by-step Execution:

2.1 Source Compilation (javac)

javac MyProgram.java
  • Converts .java.class (bytecode)
  • Bytecode is platform-independent

2.2 JVM Startup (java command)

java MyProgram

When executed:

  1. OS creates new process

  2. JVM instance is created inside that process

  3. JVM allocates:

    • Heap
    • Method Area (Metaspace)
    • Code Cache for JIT
    • Thread stacks
  4. Bootstraps necessary system classes (String, System, Thread)

2.3 Class Loading

The Class Loader Subsystem loads:

  • MyProgram.class
  • Dependent classes
  • JDK library classes

It performs:

  • Loading
  • Verification
  • Preparation
  • Resolution
  • Initialization

2.4 Bytecode Execution

The Execution Engine handles the program using:

1. Interpreter

  • Reads and executes bytecode instruction-by-instruction
  • Fast startup but slow for repeated code

2. JIT (Just-In-Time) Compiler

  • Detects frequently executed ("hot") code
  • Compiles bytecode → native machine code
  • Stores compiled code in Code Cache
  • JVM switches execution to native code → massive performance boost

This hybrid model ensures:

  • Fast startup
  • High long-term performance

3. How Much Memory Does a Java Process Get?

Java allows you to control heap allocation.

Minimum Heap:

-Xms<size>

Maximum Heap:

-Xmx<size>

Example:

java -Xms512m -Xmx4g MyProgram

If memory exceeds -Xmx → JVM throws:

java.lang.OutOfMemoryError: Java heap space

Other Memory Regions Allocated to a Process:

Region Purpose
Heap Objects, arrays
Metaspace Class metadata
Thread Stacks Local variables, frames
Code Cache JIT compiled machine code
Native Memory Libraries, buffers

4. OS-Level Process Memory Layout

Regardless of language, OS allocates typical memory segments:

+-------------------------------+
| Code Segment (Text)           |
| - JVM executable machine code |
+-------------------------------+
| Data Segment                  |
| - Global variables            |
| - Static data                 |
+-------------------------------+
| Heap                          |
| - Runtime allocated objects   |
+-------------------------------+
| Stack (per thread)            |
| - Local vars, frames          |
+-------------------------------+
| Registers                     |
| - PC, SP, general regs        |
+-------------------------------+

5. JVM Memory Model (Inside the Process)

JVM has its own logical memory structure:

+--------------------------------------+
|  Method Area (Metaspace)             |
+--------------------------------------+
|  Heap (Young + Old Gen)              |
+--------------------------------------+
|  JVM Stack (per thread)              |
+--------------------------------------+
|  PC Register (per thread)            |
+--------------------------------------+
|  Native Method Stack (per thread)    |
+--------------------------------------+

5.1 Method Area / Metaspace

Stores:

  • Class structure
  • Static variables
  • Constant pool
  • Method bytecode
  • Reflection data

Java 8+ uses Metaspace (native memory), not PermGen.

5.2 Heap (Shared by All Threads)

Largest memory area. Stores:

  • Objects
  • Arrays
  • Class instances

Divided into:

Area Purpose
Eden New objects
Survivor S0/S1 Objects that survived Minor GC
Old Gen Long-lived objects

5.3 JVM Stack (Thread-Specific)

Each thread gets its own stack.

Holds:

  • Local variables
  • Method call frames
  • Return addresses
  • Primitive variables
  • References to objects (actual objects in heap)

Stack memory is limited → recursion can cause:

java.lang.StackOverflowError

5.4 PC Register (Thread-Specific)

Each Java thread has a separate Program Counter storing the next instruction to execute.

PC is critical for:

  • Multithreading
  • Context switching
  • Keeping track of execution flow

5.5 Native Method Stack

Used for JNI (Java Native Interface):

  • C/C++ code execution
  • Native library calls

6. What Is a Thread?

A thread is the smallest execution unit inside a process.

A process can have multiple threads, all sharing:

  • Heap
  • Method Area
  • Code Cache

But having separate:

  • Stack
  • PC register
  • Native stack

7. Thread Lifecycle and Memory Usage

NEW → RUNNABLE → RUNNING → BLOCKED/WAITING → TERMINATED

Memory Allocation Per Thread

Region Purpose
Java Stack Method frames, locals
PC Register Next instruction
Native Stack JNI calls

8. Context Switching (Important)

Context switching allows CPU to switch between threads.

What Gets Saved?

When switching threads:

  • Program Counter (PC)
  • Registers
  • Stack pointer
  • Thread-specific state

Cost:

Context switching is:

  • CPU intensive
  • Expensive for large thread counts
  • Can slow down program if too many threads are created

Thus ExecutorService thread pools are preferred.


9. Combined Execution Flow

1. Programmer runs "java MyApp"
2. OS creates a new process
3. JVM instance starts inside that process
4. Class loaders load necessary classes
5. JVM creates main thread
6. Execution Engine interprets bytecode
7. JIT compiles hot code → machine code
8. Threads execute instructions
9. GC manages heap memory
10. Program ends → JVM shuts down → process destroyed

10. Additional Deep Concepts

10.1 Code Cache (JIT Area)

JVM maintains a special memory where native machine code generated by JIT is stored.

Benefits:

  • Faster repeated execution
  • Reduced interpretation
  • Native-level performance

10.2 Thread Creation Cost

Creating a thread consumes:

  • Memory (stack)
  • Scheduling overhead
  • OS kernel resources

Hence Java frameworks use:

  • Cached thread pools
  • Fixed thread pools
  • ForkJoinPool

10.3 Impact on Garbage Collection

More threads may:

  • Increase GC pauses
  • Put pressure on heap
  • Cause race conditions if not synchronized properly

11. Interview Questions

1. Difference between a process and a thread?

Process: independent execution unit with its own memory Thread: lightweight execution unit inside a process, shares memory


2. Does each Java program run in its own process?

Yes. Every time you start a Java application, OS creates a dedicated process containing a JVM instance.


3. What memory areas are shared between threads?

Heap, Metaspace, Code Cache.


4. What memory areas are thread-specific?

Stack, PC register, Native stack.


5. What causes OutOfMemoryError?

  • Exhausting heap (-Xmx)
  • Exhausting metaspace (-XX:MaxMetaspaceSize)
  • Running out of native memory
  • Massive thread creation
  • Memory leaks

6. What causes StackOverflowError?

Infinite recursion → stack memory exhausted per thread.


7. Why is context switching expensive?

Because CPU must save & restore thread state, flush registers, update program counters, switch stack pointers.


8. How do JIT and interpreter work together?

Interpreter runs first → JIT optimizes repeated code paths → native code execution.


9. Does each thread get its own heap?

No. Heap is shared by all threads. Each thread only gets its own stack.


10. How does JVM isolate different applications?

Each application runs in its own OS process with its own JVM instance and memory boundaries.


Key Takeaways

  • Java program execution always creates an OS-level process + JVM instance.

  • JVM memory consists of:

    • Heap
    • Metaspace
    • Thread Stacks
    • PC Registers
    • Native Stacks
    • Code Cache
  • Threads share heap but maintain individual stack and program counter.

  • JIT compilation boosts performance by converting bytecode → native code.

  • Memory limits are controlled by -Xms, -Xmx, -XX:MaxMetaspaceSize.

  • Context switching is expensive → use thread pools, not uncontrolled thread creation.

  • Understanding these internals helps optimize performance, debugging, and system design.