Skip to content

8325890: NMT: Arena Chunk value correction causes multiple errors in reporting#32044

Draft
roberttoyonaga wants to merge 1 commit into
openjdk:masterfrom
roberttoyonaga:JDK-8325890-solution3
Draft

8325890: NMT: Arena Chunk value correction causes multiple errors in reporting#32044
roberttoyonaga wants to merge 1 commit into
openjdk:masterfrom
roberttoyonaga:JDK-8325890-solution3

Conversation

@roberttoyonaga

@roberttoyonaga roberttoyonaga commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

The Problem

Historically, NMT needed special handling for mtChunk. Free heap chunks in the chunk pool were tagged with mtChunk, and they remained as mtChunk even after being pulled from the pool and assigned to arenas bearing other tags. For example, a malloc'd heap chunk block assigned to a mtCompiler arena continues to contribute “size” and “count” toward the mtChunk tag. This is problematic because that chunk memory is also accounted for in the arena’s “size” – effectively double counting the chunk’s memory.

From a user’s perspective, mtChunk means “free” heap chunks (not assigned to arenas). The internal NTM accounting had a different meaning: mtChunk = free chunks and arena chunks. This mismatch resulted in several problems:

  1. Before reporting mtChunk values to the user, NMT had to subtract the total size of all arenas from mtChunk size.
  2. This patching needed to be done at all locations reporting NMT data. This adds unnecessary complexity because multiple locations need to be aware of this special treatment for mtChunk.
  3. mtChunk malloc count was wrong. This is because arena chunk count was not tracked anywhere, so could not be deducted from mtChunk count. So mtChunk "size" is the free chunk size, but mtChunk "count" is the total chunk count. That's a conflict.
  4. This special report-time patching needed to be protected by a chunk pool lock to prevent inconsistencies.
  5. mtChunk peak size and peak count are wrong. These values are inflated by chunks assigned to arenas.
  6. Awkward delayed timing. Adjustments are made at report time instead of when ownership actually changes.
  7. NMT detail reports contain conflicting allocation info. When a chunk is assigned to an arena, the MST still reports the allocation under mtChunk. This conflicts with the NMT summary data which has removed the chunk size from the mtChunk category.

Solution

This PR makes mtChunk internally only represent free chunks. This aligns the internal meaning with what is presented externally to the user. This naturally fixes all the problems listed above.

This is done by removing the chunk memory from mtChunk when the chunk is assigned to an arena. The assigned arena then assumes responsibility for tracking that chunk’s memory. This change meshes nicely with the existing way that NMT treats arena memory explained more in the next section.

Invariants maintained

The existing way NMT treats malloc, arena, and “total” malloc memory (both internally/externally) is as follows:

  • Per-tag malloc memory: Individual mallocs and free heap chunks completely separate from arena memory.
  • Per-tag arena memory: Memory used by arenas coming from heap chunks.
  • Total malloc memory: The sum of malloc memory and arena memory

The approach in this PR does not change any of the above rules. Free chunks are counted in per-tag malloc memory, but when they are assigned to arenas they switch to being counted in per-tag arena memory. A chunk’s contribution to total malloc memory remains the same for its entire lifetime.

Breakdown of operations

  • When a chunk is created (regardless of whether it is for the pool or immediately for an arena)
    • “total malloc” size and # are incremented. This is done as part of the normal os::malloc operation.
  • When chunks are assigned to arenas (regardless of whether they are newly created or pulled from pool)
    • Increment arena size and #
    • Account chunk header size to arena’s tag
    • Decrement mtChunk size and #
    • malloc header and MST is updated
    • “total malloc” size and # remain unchanged
  • When chunks are removed from arenas (regardless of whether they came from the pool originally)
    • Decrement arena size and #
    • Deaccount chunk header size from arena’s tag
    • Increment mtChunk size and #
    • malloc header and MST is updated
    • Total malloc size and # remains unchanged
  • When chunks are destroyed (either pruned or non-standard size chunk removed from arena)
    • “total malloc” size and # are decremented. This is done as part of the normal os::free operation.
image

Notes

Mem tags needed to be incorporated into the MST hashing function. This ensures that a heap chunk in the free pool and a chunk backing an arena correctly show up as two separate allocations in an NMT detail report. Even though they have the same allocation site and stack, their tags will differ and allow them to be treated as two unique allocation blocks. Otherwise they'd be lumped together and presented to the user as a single allocation.

The "total" malloc counters are only ever touched when a chunk is created/destroyed, not when it changes hands between arenas and the free pool.

When chunks are added/removed from arenas, I also account for the chunk header size. This is a small amount but it gets excluded from the arena size (which only includes the chunk payload). The chunk header gets counted toward the arena's tag malloc size.

Updating the MST upon heap chunk ownership changes also fixes the NMT summary vs detail inconsistency.

Other Approaches considered

I also implemented an alternate solution that changes the internal meaning of malloc vs arena memory. We can consider arena memory as a subset of malloc memory such that per-tag arena size <= per-tag malloc size. And "total" malloc size is simply a sum of all per-tag malloc sizes. In this alternate solution, when a heap chunk is assigned to an arena, the allocation changes tags to the arena tag (like in my current solution) AND the new tag's malloc counters are incremented. This means that the chunk memory would show up in per-tag malloc and per-tag arena amounts. The memory is double counted like before this PR's fix, but the semantics have changed so that the per-tag arena amount is interpreted as a subset of the per-tag malloc amount.

I decided against this solution because it requires report-time patching of size/counts in order to maintain the existing meanings of values in the NMT report. It also requires extra logic to track "exclusive" malloc peaks, since now the per-tag malloc peaks include arena amounts.



Progress

  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue
  • Change must be properly reviewed (2 reviews required, with at least 1 Reviewer, 1 Author)

Issue

  • JDK-8325890: NMT: Arena Chunk value correction causes multiple errors in reporting (Bug - P4)

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/32044/head:pull/32044
$ git checkout pull/32044

Update a local copy of the PR:
$ git checkout pull/32044
$ git pull https://git.openjdk.org/jdk.git pull/32044/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 32044

View PR using the GUI difftool:
$ git pr show -t 32044

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/32044.diff

@bridgekeeper

bridgekeeper Bot commented Jul 24, 2026

Copy link
Copy Markdown

👋 Welcome back rtoyonaga! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk

openjdk Bot commented Jul 24, 2026

Copy link
Copy Markdown

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk openjdk Bot changed the title 8325890 8325890: NMT: Arena Chunk value correction causes multiple errors in reporting Jul 24, 2026
@openjdk openjdk Bot added the hotspot-runtime hotspot-runtime-dev@openjdk.org label Jul 24, 2026
@openjdk

openjdk Bot commented Jul 24, 2026

Copy link
Copy Markdown

@roberttoyonaga The following label will be automatically applied to this pull request:

  • hotspot-runtime

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk

openjdk Bot commented Jul 24, 2026

Copy link
Copy Markdown

The total number of required reviews for this PR has been set to 2 based on the presence of this label: hotspot-runtime. This can be overridden with the /reviewers command.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hotspot-runtime hotspot-runtime-dev@openjdk.org

Development

Successfully merging this pull request may close these issues.

1 participant