skip to content

In the JVM's runtime data areas, what is the program counter (PC) register, and why does the specification give every thread its own instead of sharing one?

level: juniorimportance: should knowfreq 40%

answer

  1. one pc per thread
  2. address of current bytecode = javap offset
  3. undefined during native methods
  4. smallest runtime data area
  5. pc + stack = resumable thread state

basics

~20 s

The PC register holds the address of the JVM bytecode instruction a thread is currently executing. Each thread has its own because threads run independently and interleave, so every thread must be able to resume at its own instruction after being descheduled.

solid answer

~50 s

The JVM specification gives each thread its own program counter register. It holds the address of the JVM instruction that thread is currently executing, which in practice is the bytecode offset inside the current method, the numbers on the left of a `javap -c` listing. It is per-thread for the same reason each thread has its own stack: threads run concurrently and can be preempted at any instruction. A shared PC would be destroyed by the first context switch. The per-thread PC plus the per-thread stack are exactly the state needed to suspend a thread and later continue it as if nothing happened. It is also the smallest and simplest runtime data area: conceptually one word-sized slot per thread, created when the thread starts and gone when it dies. Its value is undefined while the thread executes a native method, because native code runs under the platform's own instruction pointer, not the JVM's.

code

text · 8 lines
text
0: iconst_0
  1: istore_1
  2: iload_1
  3: bipush        10
  5: if_icmpge     14
  8: iinc          1, 1
 11: goto          2
 14: return

go deeper

for a junior

Recall the definition: per-thread, holds the address of the bytecode instruction currently executing, undefined in native methods, smallest area.

for a middle

Tie it to threading: the pc register plus the thread stack are the state that makes a thread suspendable and resumable, and explain the javap offset connection.

for a senior

Contrast the specification abstraction with HotSpot reality: interpreter bytecode pointer versus JIT native addresses, with the bci reconstructed from metadata for stack traces and deoptimization.

for a principal

Use it to frame the general principle that execution state is partitioned per thread while code and metadata are shared, and note that per-thread cost here is one word while the stack dominates thread memory budgeting.

## Where it sits The JVM specification defines several runtime data areas. Some are shared by all threads (the heap, the class-metadata area); others exist once per thread. The program counter register (pc register) is per-thread and is the smallest area of all: conceptually a single slot wide enough to hold the address of any JVM instruction, or a native pointer. ## What it holds If the thread is executing a Java method (a non-native method), the pc register contains the address of the JVM instruction currently being executed. Concretely this is an offset into the method's bytecode array. Compile a class, run `javap -c`, and you see numbers like 0, 3, 7, 12 to the left of each opcode: those offsets are the values the pc register takes as the method runs. Every branch, `goto`, and exception-handler entry in a classfile is expressed as such an offset, so the pc register is the runtime counterpart of the addressing scheme the classfile format already uses. ## Why one per thread A thread of execution is defined by two pieces of state: where it is (the instruction being executed) and what it has accumulated on the way there (its frames, locals, operand stacks). The JVM makes both per-thread. Threads are scheduled by the operating system and may be preempted between any two bytecodes, so if the execution point lived in one shared location, a switch to another thread would overwrite it and the original thread could never continue correctly. Because each thread has its own pc register and its own stack, threads are independent execution contexts. Two threads running the same method sit at different offsets in the same bytecode array at the same time; the bytecode is shared (it lives in class metadata and is read-only at runtime), while the position in it is not. ## Lifecycle and size The pc register is created when the thread is created and disappears when the thread terminates. It is not garbage collected, never grows, and holds no object references, so it plays no part in heap sizing. Its per-thread cost is a single machine word, negligible next to the thread stack (typically hundreds of kilobytes to a megabyte). ## Native methods The specification says the pc register's value is undefined when the thread is executing a native method. Native code is not JVM bytecode; it has no bytecode offsets, and its execution point is tracked by the hardware program counter of the underlying platform. The JVM makes no promise about the pc register's contents until the thread returns to a Java frame. ## Specification versus implementation The pc register is an abstraction in the specification, not necessarily a distinct field in HotSpot. An interpreter keeps the current bytecode pointer in a machine register or in the interpreter frame; JIT-compiled code has no bytecode pointer at all, only native code addresses, and the JVM reconstructs the corresponding bytecode index (bci) from compiler metadata when it needs one, for example when building a stack trace or deoptimizing. What is guaranteed is the observable behaviour: each thread has an independent, correctly maintained execution point, and stack traces report the right position for each thread.

  • What other runtime data area is per-thread, and what does it hold?
    The JVM stack is per-thread. It holds a frame for each method invocation, and each frame contains that invocation's local variable array, operand stack, and a reference to the run-time constant pool of the current class. Native method stacks, where an implementation provides them, are also per-thread.
  • If two threads run the same method at the same time, what do they share and what do they not share?
    They share the bytecode itself, the class metadata, and any heap objects and static fields they both touch. They do not share the pc register or the stack frame: each thread has its own execution offset, its own local variables, and its own operand stack for that invocation.

A bookmark: many readers can share one printed book (the bytecode), but each needs a personal bookmark to know which line to continue from after putting it down.

saying these in an interview costs you the question

  • Calling it a CPU register the JVM directly exposes; it is a specification-level abstraction and HotSpot may not keep a literal field for it
  • Saying there is one PC for the whole JVM, or one per core
  • Claiming it stores a method's return value, or the next source line, rather than the current instruction address
  • Thinking it is part of the heap or something the garbage collector manages

context