skip to content

What does the -Xss flag do, and when is increasing it the right response to a StackOverflowError?

level: seniorimportance: should knowfreq 40%

answer

  1. -Xss = per-thread stack size
  2. Bigger -Xss = deeper recursion allowed
  3. Only helps FINITE deep recursion
  4. Per-thread cost → 'unable to create native thread'
  5. Prefer iteration/explicit stack over flag tuning

basics

~10 s

-Xss sets each thread's stack size. A bigger value allows deeper recursion before a StackOverflowError. It only helps when recursion is legitimately deep but finite — it cannot fix recursion that never ends.

solid answer

~50 s

-Xss sets the per-thread call-stack size (e.g. -Xss1m). Because StackOverflowError happens when frames exhaust that stack, a larger -Xss lets a thread recurse deeper before overflowing. It is the right lever only when the recursion is genuinely deep but bounded — say, walking a legitimately long structure — and you cannot easily convert it to iteration. It is the wrong lever for infinite or accidental recursion: no finite stack survives that, so you must fix the base case instead. Raising -Xss also has a cost: every thread reserves that much, so in a highly multithreaded service a large -Xss multiplies memory use and can push you toward 'unable to create native thread'. In practice, prefer redesigning to iteration (an explicit heap-backed stack) so depth scales with heap; reach for -Xss only as a measured, documented headroom adjustment. The default is platform-dependent, commonly around 512KB–1MB.

code

java · 16 lines
java
// Recursive sum over a long list can overflow the stack.
int sumRecursive(Node n) {
    if (n == null) return 0;            // base case (must exist!)
    return n.value + sumRecursive(n.next);
}

// Iterative version: depth lives in a heap loop, not the call stack.
int sumIterative(Node n) {
    int total = 0;
    for (Node cur = n; cur != null; cur = cur.next) {
        total += cur.value;            // no growing call stack
    }
    return total;
}
// Bumping -Xss only delays overflow of the recursive form;
// the iterative form removes the limit (bounded by heap).

go deeper

for a junior

Knows -Xss controls stack size and a bigger value allows deeper recursion.

for a middle

Explains that -Xss is per-thread, can't fix infinite recursion, and that iteration is the cleaner fix.

for a senior

Weighs -Xss against total thread memory, knows the native-thread-creation failure mode, and prefers algorithmic restructuring with a documented bump only when needed.

for a principal

Sets stack-size policy across the fleet, balances recursion depth vs thread density, and bakes the iterate-don't-tune guidance into platform standards.

## What -Xss is `-Xss` is a JVM startup flag that sets the **size of each thread's call stack**. You write it as `-Xss<size>`, for example `-Xss1m` (1 megabyte), `-Xss512k`. Every **thread** the JVM creates gets a stack of this size. The stack holds one **frame** per active method call (parameters, locals, operand stack, return address). The deeper your calls nest, the more of the stack you use. ## Why it relates to StackOverflowError A `StackOverflowError` is thrown when a thread can't push another frame because its stack is full. Since `-Xss` sets how big that stack is, **increasing `-Xss` raises the depth a thread can reach before overflowing**, and decreasing it lowers that depth. So tuning `-Xss` directly moves the overflow threshold. ## When increasing -Xss is appropriate Only when the recursion (or deep call chain) is **legitimately deep but finite** and you can't readily restructure it. Examples: - A recursive descent over a real data structure that is genuinely thousands deep (a long degenerate list, a deeply nested document, an unbalanced tree). - Generated or third-party code whose call depth you can't change but is known to be bounded. In these cases the algorithm is correct; it just needs more headroom. A modest, **measured, documented** bump to `-Xss` is reasonable. ## When increasing -Xss is the wrong fix - **Infinite or accidental recursion** (missing base case, mutual recursion, a `toString`/getter calling itself). No finite stack survives unbounded growth — you'd just overflow a bit later. The fix is the **base case**, not the flag. - **When iteration is feasible.** Converting recursion to a loop with an **explicit, heap-allocated stack/queue** moves the depth budget from the small per-thread stack to the large heap, which usually scales far better and removes the cliff entirely. ## The cost of a larger -Xss `-Xss` is **per thread**. If your service runs hundreds or thousands of threads (classic thread-per-request servers, large pools), multiplying each thread's stack by a few hundred KB multiplies total memory. Past a point this manifests as **`OutOfMemoryError: unable to create native thread`**, because the OS/process can't reserve stack space for new threads. So `-Xss` trades single-thread depth against total thread capacity — a system-level decision, not a free knob. Conversely, in thread-heavy systems you sometimes **lower** `-Xss` deliberately to fit more threads, accepting shallower recursion. ## Defaults and portability The default stack size is **platform- and JVM-dependent** (commonly on the order of 512KB to 1MB on 64-bit HotSpot). Don't assume a specific value across OS/arch; if you rely on deep recursion, set `-Xss` explicitly so behaviour is reproducible. ## Recommended decision order 1. Confirm the recursion is **finite** (read the trace: a true cycle that never terminates = bug, fix the base case). 2. If finite and deep, prefer **iteration / explicit stack** so depth is heap-bound. 3. Only if restructuring is impractical, **raise `-Xss` deliberately**, measure the memory impact across all threads, and document why.

  • Your service throws StackOverflowError under load only at high thread counts. What's the tension if you raise -Xss?
    Each thread reserves the larger stack, so total memory grows with thread count and you risk 'unable to create native thread'. You'd weigh per-request depth against pool size, and likely prefer making the algorithm iterative instead.
  • How would you make a deeply recursive tree traversal safe without touching -Xss?
    Replace call recursion with an explicit loop driven by a heap-allocated Deque/stack (push children, pop and process). Depth is then bounded by heap memory, which scales far beyond the per-thread stack.

saying these in an interview costs you the question

  • Claiming -Xss fixes infinite recursion
  • Ignoring that -Xss multiplies across all threads
  • Assuming a fixed default stack size across platforms
  • Reaching for -Xss before checking whether the recursion is even bounded

context