skip to content

The JVM specification defines StackOverflowError or OutOfMemoryError conditions for most runtime data areas, but defines no error condition for the program counter register. Why is that consistent?

level: seniorimportance: nice to knowfreq 15%

answer

  1. errors attach to growable areas
  2. pc is fixed-width, one per thread
  3. recursion costs frames not pcs
  4. no flag sizes the pc register
  5. unable to create native thread = stacks/OS limits

basics

~20 s

Because it is fixed-size and allocated once per thread. It never grows with recursion or allocation, so it cannot be exhausted. The only adjacent failure is being unable to create a thread at all, reported as OutOfMemoryError on thread creation.

solid answer

~50 s

Every runtime data area with an error condition is one whose size depends on program behaviour: the heap grows with allocation and throws `OutOfMemoryError`, the JVM stack grows with invocation depth and throws `StackOverflowError` (or `OutOfMemoryError` if a dynamically expanding stack cannot be extended), and the class-metadata area grows as classes are loaded and can exhaust Metaspace. The pc register is different in kind: a single fixed-width slot created when the thread is created and released when it dies. Nothing a program does makes it bigger. Deep recursion consumes frames, not pc registers; heavy allocation consumes heap, not pc registers. So there is no exhaustion mode to specify, and correspondingly no flag to size it. The only related failure is that the JVM may be unable to create a new thread at all, which surfaces as `OutOfMemoryError: unable to create native thread`. That is a failure to obtain a thread's stack and OS resources, not a pc register limit.

code

text · 4 lines
text
java.lang.StackOverflowError                                # too many frames on one thread stack (-Xss)
java.lang.OutOfMemoryError: Java heap space                 # allocation outran the heap (-Xmx)
java.lang.OutOfMemoryError: Metaspace                       # class metadata exhausted
java.lang.OutOfMemoryError: unable to create native thread  # OS/native memory for a new thread

go deeper

for a junior

State simply that it is one fixed-size slot per thread that never grows, so there is nothing to exhaust.

for a middle

Contrast it with the growable areas and name their error conditions: heap, JVM stack, class metadata.

for a senior

Connect to diagnosis: map each failure message to its area and knob, and explain why unable to create native thread is about stacks and OS limits rather than a JVM-managed area overflowing.

for a principal

Use it when reasoning about thread-count capacity: per-thread cost is dominated by stack reservation and OS bookkeeping, which is a real argument in pooling and lightweight-thread decisions.

## The pattern behind the specification's error conditions The JVM specification attaches error conditions to areas whose size depends on program behaviour. - **Heap** — allocation can outrun available memory, giving `OutOfMemoryError: Java heap space`. - **JVM stack** — a fixed-size stack that a thread outgrows gives `StackOverflowError`; an expandable stack that cannot be expanded gives `OutOfMemoryError`. - **Method area / class metadata** — loading more classes can exhaust it (Metaspace in HotSpot). - **Native method stacks**, where provided — the same two conditions as JVM stacks. The pc register is not on that list because its size is invariant. It is one slot, allocated with the thread, wide enough to hold an instruction address (or an unspecified value while in native code). No operation makes it larger by repetition, so exhaustion is not expressible. ## Where the real cost of a thread lives When reasoning about how many threads a JVM can run, the pc register contributes essentially nothing. The dominant per-thread costs are the JVM stack (reserved size set by `-Xss`, commonly a few hundred kilobytes to a megabyte, committed lazily by the OS), any native stack, and OS thread bookkeeping. If thread creation fails you see `OutOfMemoryError: unable to create native thread`, which normally means the process hit an OS or container limit on threads, or exhausted address space or native memory for stacks — not that any JVM-managed data area overflowed. ## Why this is worth understanding rather than memorising It is a clean check on whether a candidate understands what each area does. Someone who thinks the pc register accumulates return addresses will expect it to overflow on recursion; someone who understands that nesting is expressed by frames knows recursion depth is bounded by stack size instead. The same reasoning tells you which knob to turn under failure: `-Xss` for `StackOverflowError`, `-Xmx` or an allocation fix for heap exhaustion, `MaxMetaspaceSize` or a classloading investigation for metaspace, and fewer or smaller thread stacks for `unable to create native thread`. There is no knob for the pc register, and the absence of any flag to size it is itself a hint that it cannot be a bottleneck. ## A precise way to say it in an interview The pc register is per-thread but not per-frame, fixed-width, and never grows. Areas get error conditions when their consumption is program-dependent; the pc register's consumption is thread-count-dependent only, and the thread-count failure mode already has its own reporting through thread creation failure.

  • Which JVM flag sizes the program counter register?
    None exists. Its width is fixed by the implementation at a single machine word per thread. The tunable per-thread memory knob is -Xss, which sizes the thread stack, the area that actually grows with invocation depth.
  • A service dies with OutOfMemoryError: unable to create native thread while heap usage is low. What is going on?
    The process could not obtain the resources for another thread: typically an OS or container limit on threads or processes, exhausted native memory or address space for stacks, or a large -Xss multiplied by many threads. The fix is bounding thread counts through pooling, lowering -Xss if frames allow, or raising the limit — not raising -Xmx.

saying these in an interview costs you the question

  • Claiming StackOverflowError comes from the pc register overflowing
  • Inventing a tuning flag for the pc register
  • Raising -Xmx in response to unable to create native thread, which usually needs fewer threads or smaller stacks
  • Assuming the pc register is a meaningful part of per-thread memory footprint

context