Skip to content

Enable live heap profiling by default on safe JVM versions#11039

Draft
jbachorik wants to merge 1 commit intomasterfrom
jb/live_heap_default
Draft

Enable live heap profiling by default on safe JVM versions#11039
jbachorik wants to merge 1 commit intomasterfrom
jb/live_heap_default

Conversation

@jbachorik
Copy link
Copy Markdown
Contributor

@jbachorik jbachorik commented Apr 2, 2026

What Does This Do

Adds a unified config key profiling.liveheap.enabled that auto-detects safe systems and enables live heap profiling by default. The ddprof native library is preferred, with JFR jdk.OldObjectSample as an automatic fallback.

Introduces profiling.jfr.liveheap.enabled as the replacement for the deprecated profiling.heap.enabled, with context-aware deprecation warnings. Cross-awareness between ddprof and JFR paths prevents double collection and warns when live heap profiling becomes effectively inactive.

Enablement Logic

flowchart TD
    A["profiling.liveheap.enabled\n(unified master switch)"]
    A -->|"false"| B["ALL live heap OFF\n(ddprof + JFR)"]
    A -->|"unset or true"| C{Split into two paths}

    C --> D["ddprof path\nDatadogProfilerConfig"]
    C --> E["JFR path\nOpenJdkController"]

    D --> JFRCHK{"profiling.jfr.liveheap.enabled\nexplicitly true?"}
    JFRCHK -->|yes| JFRDIS["ddprof MEMLEAK OFF\n⚠️ warn: JFR explicitly requested,\ndisabling ddprof (superior mode)\nto avoid double collection"]
    JFRCHK -->|no| F["profiling.ddprof.liveheap.enabled"]
    F -->|"false"| G["MEMLEAK OFF"]
    F -->|"unset or true"\ndefault = isJmethodIDSafe| H{"JVM safe?\nJava 8, 11.0.23+,\n17.0.11+, 21.0.3+, 22+"}
    H -->|yes| I[MEMLEAK ON]
    H -->|no| J["MEMLEAK ON\n⚠️ warn: not stable on this JVM"]

    G --> GCHK{"JFR OldObjectSample\navailable?"}
    GCHK -->|no| GWARN["⚠️ warn: live heap\nwill be inactive"]
    GCHK -->|yes| GOK[JFR fallback active]

    E --> K{"Which key is set?"}
    K -->|"profiling.jfr.liveheap.enabled"| L{value?}
    K -->|"profiling.heap.enabled\n(deprecated)"| DEP{ddprof likely active?}
    K -->|"neither set"| NOKEY{"ddprof likely\nactive?"}

    L -->|"true"| L1[OldObjectSample ON]
    L -->|"false"| LCHK{"ddprof likely\nactive?"}
    LCHK -->|yes| L2[OldObjectSample OFF]
    LCHK -->|no| L2WARN["OldObjectSample OFF\n⚠️ warn: live heap\nwill be inactive"]

    NOKEY -->|yes| NOKEY_OFF["OldObjectSample OFF\n(ddprof handles live heap)"]
    NOKEY -->|no| NOKEY_JFP{"JVM supports it?\nJava 11.0.12+,\n17.0.3+, 18+"}
    NOKEY_JFP -->|yes| O["OldObjectSample ON\n(JFR fallback)"]
    NOKEY_JFP -->|no| P[OldObjectSample OFF]

    DEP -->|yes| DEP1["⚠️ warn: has no effect\n(ddprof handles live heap)\nkey ignored"]
    DEP -->|"no, value=true"| DEP2["⚠️ warn: redundant\n(JFR already on by default)"]
    DEP -->|"no, value=false"| DEP3["⚠️ warn: use new key\nprofiling.jfr.liveheap.enabled"]
    DEP2 --> DEP_ON[OldObjectSample ON]
    DEP3 --> DEP_OFF[OldObjectSample OFF]

    style B fill:#f66,color:#fff
    style G fill:#f66,color:#fff
    style JFRDIS fill:#fa0,color:#fff
    style L2 fill:#f66,color:#fff
    style L2WARN fill:#f66,color:#fff
    style NOKEY_OFF fill:#69c,color:#fff
    style P fill:#f66,color:#fff
    style DEP_OFF fill:#f66,color:#fff
    style GWARN fill:#fa0,color:#fff
    style I fill:#6b6,color:#fff
    style J fill:#fa0,color:#fff
    style L1 fill:#6b6,color:#fff
    style O fill:#6b6,color:#fff
    style GOK fill:#6b6,color:#fff
    style DEP_ON fill:#6b6,color:#fff
    style DEP1 fill:#fd6,color:#333
    style DEP2 fill:#fd6,color:#333
    style DEP3 fill:#fd6,color:#333
Loading

Note: When ddprof MEMLEAK is active, disableOverriddenEvents() at recording start also disables jdk.OldObjectSample as a safety net. The proactive disable in the constructor ensures the settings map is consistent from the start.

Motivation

Live heap profiling provides valuable memory leak detection but was previously opt-in (profiling.ddprof.liveheap.enabled defaulted to false). Users had to know about and explicitly enable it.

This change makes it enabled by default on safe systems, matching the pattern already used by allocation profiling. The two live heap mechanisms (ddprof native and JFR OldObjectSample) are now unified under a single flag with automatic fallback.

[PROF-14188]

Additional Notes

  • isMemoryLeakProfilingSafe() returns true when at least one safe mechanism is available: isJmethodIDSafe() || isOldObjectSampleAvailable()
  • The ddprof-specific key default changed from hardcoded false to dynamic isJmethodIDSafe()
  • Cross-awareness between paths:
    • profiling.jfr.liveheap.enabled=true disables ddprof MEMLEAK on user request (avoids double collection)
    • profiling.ddprof.liveheap.enabled=false with no JFR fallback warns about inactive live heap
    • profiling.jfr.liveheap.enabled=false with no ddprof warns about inactive live heap
    • No explicit JFR key + ddprof active: OldObjectSample proactively disabled (no double collection)
  • Deprecation warnings for profiling.heap.enabled are context-aware:
    • When ddprof handles live heap: "has no effect" (key ignored)
    • When JFR fallback, value=true: "redundant"
    • When JFR fallback, value=false: "use new key instead"
  • Pre-existing bug fixed: isEventEnabled was called with jdk.OldObjectSample#enabled which resulted in a double #enabled lookup, making the warning dead code

Contributor Checklist

Jira ticket: [PROF-14188]

Note: Once your PR is ready to merge, add it to the merge queue by commenting /merge. /merge -c cancels the queue request. /merge -f --reason "reason" skips all merge queue checks; please use this judiciously, as some checks do not run at the PR-level. For more information, see this doc.

@jbachorik jbachorik added comp: profiling Profiling type: enhancement Enhancements and improvements tag: ai generated Largely based on code generated by an AI or LLM labels Apr 2, 2026
@jbachorik jbachorik force-pushed the jb/live_heap_default branch 4 times, most recently from 43f65b1 to 019c0b1 Compare April 2, 2026 12:50
Adds unified config key `profiling.liveheap.enabled` that auto-detects
safe systems (isJmethodIDSafe || isOldObjectSampleAvailable) and enables
live heap profiling by default. Ddprof native library is preferred with
JFR OldObjectSample as fallback.

New `profiling.liveheap.jfr.enabled` replaces deprecated
`profiling.heap.enabled` with context-aware deprecation warnings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jbachorik jbachorik force-pushed the jb/live_heap_default branch from 019c0b1 to e9f2f3f Compare April 2, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: profiling Profiling tag: ai generated Largely based on code generated by an AI or LLM type: enhancement Enhancements and improvements

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant