Repository navigation
Heap exhaustion returns null to the allocating thread instead of throwing OutOfMemoryError #647
Copy link
Copy link
Open
Labels
agent/skipThe agent decided this issue is out of scope; see comment for reason.The agent decided this issue is out of scope; see comment for reason.area/vmJVM internals: JIT compilers, GC, VM magic, type system.JVM internals: JIT compilers, GC, VM magic, type system.kind/bugConfirmed bug report with a repro or stack trace.Confirmed bug report with a repro or stack trace.
Description
Activity
- addedkind/bugConfirmed bug report with a repro or stack trace.Confirmed bug report with a repro or stack trace.area/vmJVM internals: JIT compilers, GC, VM magic, type system.JVM internals: JIT compilers, GC, VM magic, type system.
on Sep 17, 2026 - addedno-autoSkip all automation; human drives via /oc and /run only.Skip all automation; human drives via /oc and /run only.
on Sep 24, 2026 /oc triage
Reacted by Levente SánthaTriage
- Area: area/vm (suspected
org.jnode.vm.memDef.DefaultHeapManagerGC/allocation path; root cause unconfirmed) - Kind: kind/bug (stack and actual/expected behavior are reported)
- Repro: needs more info from reporter
- Blast radius: L5 system (heap allocation/GC path, VM-wide failure mode, boot/QEMU proof required)
- Expected scope:
DefaultHeapManager.allocObject/allocHeapOOM delivery and focused regression coverage; exact lines and minimal fix pending. Do not change ASM, public API, or unrelated heap policy unless required. - Test path: tentative
sh build.sh x86plus a QEMU/VirtualBox boot test that fills the heap and verifiesOutOfMemoryErrordelivery; exact commands pending. - Merge signal: human-review (bug on an L5 VM-wide allocation/GC path)
- Gaps: blocking: exact build target and commit; exact boot/run commands; numbered reproducible workload/test attachment
- Suggested next: needs-info
- Split proposal: none yet; keep as one VM allocation-path issue if the focused fix stays within the heap manager and regression tests
- Labels applied: kind/bug, area/vm, no-auto (no removals; no-auto retained)
Needs the following before work can start:
- Provide the exact commit SHA and
sh build.sh <target>command used. - Provide the complete QEMU or VirtualBox boot/run command, including memory and architecture, and confirm whether boot reached
System has finished. - Provide numbered shell/test-harness steps or the attached workload/testlet artifact, including how the heap is sized, plus a 20–60 line UART1 excerpt around the failure if available.
- Area: area/vm (suspected
Triage
- Area: area/vm (suspected
org.jnode.vm.memDef.DefaultHeapManagerGC/allocation path; root cause unconfirmed) - Kind: kind/bug (stack and actual/expected behavior are reported)
- Repro: needs more info from reporter
- Blast radius: L5 system (heap allocation/GC path, VM-wide failure mode, boot/QEMU proof required)
- Expected scope:
DefaultHeapManager.allocObject/allocHeapOOM delivery and focused regression coverage; exact lines and minimal fix pending. Do not change ASM, public API, or unrelated heap policy unless required. - Test path: tentative
sh build.sh x86plus a QEMU/VirtualBox boot test that fills the heap and verifiesOutOfMemoryErrordelivery; exact commands pending. - Merge signal: human-review (bug on an L5 VM-wide allocation/GC path)
- Gaps: blocking: exact build target and commit; exact boot/run commands; numbered reproducible workload/test attachment
- Suggested next: needs-info
- Split proposal: none yet; keep as one VM allocation-path issue if the focused fix stays within the heap manager and regression tests
- Labels applied: kind/bug, area/vm, no-auto (no removals; no-auto retained)
- Area: area/vm (suspected
- addedagent/needs-infoThe agent has posted clarifying questions; waiting for the reporter.The agent has posted clarifying questions; waiting for the reporter.and removedno-autoSkip all automation; human drives via /oc and /run only.Skip all automation; human drives via /oc and /run only.
on Sep 24, 2026 /run
/oc Please proceed with this task.
Reacted by Levente Sántha- addedagent/in-progressThe OpenCode agent is currently working on this issue.The OpenCode agent is currently working on this issue.
on Sep 24, 2026 🤖 Working on this. Run:
2026-09-24T22:09:43.501Z
Plan: trace OOM delivery, add focused regression coverage, then build and verify the VM path.Plan
- Trace
DefaultHeapManager.allocObjectandallocHeapfailure semantics. - Compare OOM handling across allocation entry points and heap managers.
- Add the smallest regression test for exception delivery.
- Run the focused core test suite and x86 build.
- Review the final diff for Java 1.6 and VM-path safety.
- Trace
🤖 Refusal — needs more info
- Why this matches: The reported null result does not match the current allocator control flow.
DefaultHeapManager.allocObjectperforms a synchronous GC and retry, then throws the preallocatedOutOfMemoryErroratcore/src/core/org/jnode/vm/memmgr/def/DefaultHeapManager.java:320-338; its normal exit at line 378 is a non-null object. - Log interpretation:
ret null.anddebugStackTrace()are emitted by the low-level native-block allocator atcore/src/core/org/jnode/vm/MemoryBlockManager.java:123-131.DefaultHeapManager.allocHeapconverts that sentinel tonullinternally, butallocObjectdoes not return it after exhaustion. - Likely observed failure: The serial input pump itself allocates at
core/src/driver/org/jnode/driver/serial/console/RawKeyboardReader.java:85and has noOutOfMemoryErrorrecovery. This explains loss of the management console after OOME, but preserving system threads requires a separate heap-reserve/resilience design and is outside the claimed null-delivery fix. - What I did not do: I made no source changes and did not run a build/boot test because the reported behavior cannot be reproduced from the current source and no exact build commit or workload was provided.
- Needed to proceed:
- Exact commit SHA and ISO build target used on 2026-09-17.
- Exact QEMU/VirtualBox command and heap-sizing configuration.
- Numbered workload or test artifact showing the workload thread catching
OutOfMemoryError, separate from the serial input pump failure. - UART excerpt showing the OOME delivery/failure point before any console input allocation.
Confidence: high for the current-source control flow; the reported guest behavior remains tied to the missing revision/repro.
- Why this matches: The reported null result does not match the current allocator control flow.
No code changes made. The current allocator already throws OOME at
core/src/core/org/jnode/vm/memmgr/def/DefaultHeapManager.java:338; posted a needs-info report explaining the low-levelret nulllog and requesting the exact commit/reproduction.- addedagent/skipThe agent decided this issue is out of scope; see comment for reason.The agent decided this issue is out of scope; see comment for reason.and removedagent/needs-infoThe agent has posted clarifying questions; waiting for the reporter.The agent has posted clarifying questions; waiting for the reporter.agent/in-progressThe OpenCode agent is currently working on this issue.The OpenCode agent is currently working on this issue.
on Sep 24, 2026
Metadata
Metadata
Assignees
Labels
agent/skipThe agent decided this issue is out of scope; see comment for reason.The agent decided this issue is out of scope; see comment for reason.area/vmJVM internals: JIT compilers, GC, VM magic, type system.JVM internals: JIT compilers, GC, VM magic, type system.kind/bugConfirmed bug report with a repro or stack trace.Confirmed bug report with a repro or stack trace.


Summary
When the Java heap is exhausted, the allocator returns
nullto the allocating thread instead of throwingOutOfMemoryErrorin it. The thread stumbles on with a null reference, producing cascading secondary failures, and the guest freezes hard (no prompt, Ctrl-C ineffective, no panic) instead of failing the offending allocation cleanly.Environment
0.2.9-dev(x86 32-bit), VirtualBox 7.2.6, guest 1024 MB then 2048 MB RAMReproduction
Run a workload that accumulates unreachable-but-uncollectable state until the heap fills — in our case, repeated whole-class JIT compiles (
VmType.compileRuntime) across ~25 mauve testlets in one VM lifetime (no class unloading, so compiled code/IR/loaders accumulate). Eventually the KDB log shows repeating:and the VGA console shows e.g.:
Note the victim here is the serial console's own keyboard-pump thread dying inside
LinkedList.addLast— i.e. once the heap is full, even the management console cannot allocate, so the guest is unmanageable (serial + VGA dead, only poweroff works). The allocating thread gotnull, not an exception.Expected behavior
After a full GC, the allocating thread should receive a catchable
java.lang.OutOfMemoryError(per JLS 11.1 / JVM spec), letting the application fail fast while the rest of the VM — especially console/management threads — stays alive. At minimum, system threads should be insulated from user-heap exhaustion.Suspected component
org.jnode.vm.memDef.DefaultHeapManager::allocObject/allocHeapOOM path (returns null; the<oom/>marker +debugStackTracesuggest the detection exists but the delivery as a thrown error does not).Impact
Any long-running guest workload that grows the heap eventually bricks the VM with no diagnosis and no recovery short of poweroff + snapshot restore. This turned a routine 50-test sweep into repeated freeze/restore cycles during L2-compiler differential testing.
Triage Addendum (auto, 2026-09-24)
DefaultHeapManager.allocObject/allocHeapOOM delivery and focused regression coverage; exact lines and minimal fix pending; no ASM, public API, or unrelated heap-policy changes unless required.sh build.sh x86plus a QEMU/VirtualBox boot test that fills the heap and verifiesOutOfMemoryErrordelivery; exact commands pending.## Triagecomment below.✅ Ticket Runner Status