Skip to content

Cap the whole Java heap in browsers with a maxHeap option - #57

Merged
Project516 merged 1 commit into
masterfrom
p516/browser-heap-cap
Nov 6, 2026
Merged

Project516 merged 1 commit into
masterfrom
p516/browser-heap-cap

Conversation

@Project516

Copy link
Copy Markdown
Owner

Pages can now cap the Java heap with cheerpjInit({ maxHeap: "256m" }). Before, the browser capped only a single array, so a program that kept allocating grew until the tab died. Under Node, -Xmx already caps the whole heap.

maxHeap takes bytes or a size with k, m or g, as -Xmx does: at least 2 MB, at most 1 GB. It sets what Runtime.maxMemory() reports, and CheerpJ has no such option.

How the browser measures the heap:

  • The VM runs in a Worker. There, performance.memory and measureUserAgentSpecificMemory() are missing, so the VM counts live memory itself. It adds up arrays of 4 KB or more from allocation until a FinalizationRegistry callback reports them collected.
  • The check works as it does under Node: a counter, a reading every step, and an error only when the cap is still passed.
  • Browsers have no gc(), so a dropped array keeps counting until the engine collects it. Over the cap, the VM allocates a throwaway 256 MB ArrayBuffer, which makes Chromium collect, and pauses its threads a few milliseconds at a time. It throws OutOfMemoryError: Java heap space once finalizers have been quiet for 100 ms with the sum still over the cap, or after 1 s over. A smaller 64 MB push gave false errors.
  • Without FinalizationRegistry, or without maxHeap, only the per-array cap applies.

Results in headless Chromium, filling a list with 256 KB arrays until the error, clearing it, churning garbage, and filling again, 8 rounds per cap:

maxHeap false errors held when stopped
32m 0 of 16 about 1.3x the cap
64m 0 of 8 about 1.12x
128m 0 of 8 about 1.09x
256m 0 of 8 about 1.06x

The error came about 0.1 s after the cap. Allocation-heavy code shows no cost from the counting: 400k 8 KB arrays plus 6M small objects ran in 1170 ms on master and 1180 ms here, within the 1069 to 1367 ms spread. The browser self-test's javac compile showed no difference beyond its run-to-run spread.

Tests:

  • test/heapcheck.test.ts covers the counting and the lazy check.
  • pnpm typecheck and pnpm test pass.
  • docs/browser.md has a "Memory limit" section.

Noticed, not fixed:

  • Objects and arrays under 4 KB do not count, so a program that only allocates those is not capped.
  • Only Chromium was run. Firefox and Safari may collect later and stop a program further past the cap.

@coderabbitai

coderabbitai Bot commented Nov 6, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: e162dab9-0398-482e-b450-4880326b4e54
Commits

Reviewing files that changed from the base of the PR and between d6b2c5d and 9f3542f.

Files selected for processing: 11

  • docs/browser.md
  • docs/node.md
  • src/browser/api.ts
  • src/browser/protocol.ts
  • src/browser/worker.ts
  • src/heapsize.ts
  • src/interp.ts
  • src/jvm.ts
  • src/node.ts
  • src/runtime.ts
  • test/heapcheck.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@project516-review-bot project516-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds a maxHeap option to cheerpjInit() that caps the total Java heap in browsers, mirroring Node's -Xmx behavior. The browser worker tracks live memory by counting arrays ≥4 KB from allocation until FinalizationRegistry finalizers report collection. When the sum exceeds the cap, a 256 MB throwaway ArrayBuffer nudges Chromium to collect, and the VM pauses threads; OutOfMemoryError is thrown after 100 ms of finalizer quiet or 1 s total over the cap. Validation accepts bytes or -Xmx-style strings (k/m/g, 2 MB 1 GB). Documentation and tests are included.


review-bot, model nvidia/nemotron-3-ultra-550b-a55b:free, verdict approve

@Project516
Project516 merged commit b805c11 into master Nov 6, 2026
16 checks passed
@Project516
Project516 deleted the p516/browser-heap-cap branch November 6, 2026 01:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant