oracle/graal · warning · PermanentBailoutException
Cannot handle %d variables in %d loops
Error message
Cannot handle %d variables in %d loops
What it means
Thrown by LinearScanLifetimeAnalysisPhase.computeLocalLiveSets when allocating the per-variable/per-loop BitMap2D (variables x loops bits) fails: either the bit count exceeds Integer.MAX_VALUE or the allocation throws OutOfMemoryError. The linear-scan allocator cannot track loop membership for such a huge variable/loop product, so the compilation permanently bails out wrapping the OOM.
Source
Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java:186
}
/**
* Computes local live sets (i.e. {@link BlockData#liveGen} and {@link BlockData#liveKill})
* separately for each block.
*/
@SuppressWarnings("try")
void computeLocalLiveSets() {
int liveSize = allocator.liveSetSize();
int variables = allocator.operandSize();
int loops = allocator.numLoops();
long nBits = (long) variables * loops;
try {
if (nBits > Integer.MAX_VALUE) {
throw new OutOfMemoryError();
}
intervalInLoop = new BitMap2D(variables, loops);
} catch (OutOfMemoryError e) {
throw new PermanentBailoutException(e, "Cannot handle %d variables in %d loops", variables, loops);
}
try {
final SparseBitSet liveGenScratch = new SparseBitSet();
final SparseBitSet liveKillScratch = new SparseBitSet();
// iterate all blocks
for (int blockId : allocator.sortedBlocks()) {
BasicBlock<?> block = allocator.getLIR().getBlockById(blockId);
try (Indent indent = debug.logAndIndent("compute local live sets for block %s", block)) {
liveGenScratch.clear();
liveKillScratch.clear();
ArrayList<LIRInstruction> instructions = allocator.getLIR().getLIRforBlock(block);
int numInst = instructions.size();
ValueConsumer useConsumer = (operand, mode, flags) -> {
if (LIRValueUtil.isVariable(operand)) {View on GitHub (pinned to a66e9ccd1d)
Solutions
- If variables*loops is genuinely near Integer.MAX_VALUE, refactor the method (split it, reduce loop count) — no flag fixes the structural limit.
- If the container is merely low on memory, raise the JVM's heap budget so the bit set allocation succeeds.
- Check -XX:CompileCommand filtering for the offending mega-method to exclude it from Graal compilation.
Defensive patterns
Strategy: fallback
Try / catch
// permanent bailout; if caused by heap pressure rather than the 2^31 limit, // raising -Xmx lets the same method compile on retry.
Prevention
- Keep generated mega-methods under control (split by region/statement batches).
- Size the JVM heap for JIT compilation load, not just application load.
When it happens
Trigger: new BitMap2D(variables, loops) throwing OutOfMemoryError (or nBits > Integer.MAX_VALUE throwing it explicitly) — a method with an enormous number of LIR variables (many virtual registers after register allocation setup) multiplied by many loops, e.g. tens of thousands of variables times thousands of loops.
Common situations: Machine-generated mega-methods (query compilers, state machines, shader-like kernels); methods whose inlining exploded variable counts; memory-constrained containers where even a legal-size allocation fails — the message reports the exact variables/loops counts to distinguish a real limit breach from a tight -Xmx/-XX:MaxHeapSizeForCompilation.
Related errors
- Out-of-memory during live set allocation of size %d
- too many iterations in computeGlobalLiveSets
- LinearScan: no register found
- OSR compilation without OSR entry loop.
- OSR with locks disabled.
AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14).
Data as JSON: /api/errors/4a4a083ab48763be.
Report an issue: GitHub.