Skip to content

Add V8 JS metric for absolute heap size limit from v8.getHeapStatistics().heap_size_limit #3476

@Hronom

Description

@Hronom

Is your feature request related to a problem? Please describe.

The current V8 JS engine runtime metrics are all sourced from v8.getHeapSpaceStatistics(), which provides per-space breakdowns (space_size, space_used_size, space_available_size, physical_space_size).

However, there is no metric for the absolute maximum heap size — the hard ceiling controlled by --max-old-space-size (or V8's default). This value is available from v8.getHeapStatistics().heap_size_limit and represents the maximum size the V8 heap can grow to before the process crashes with a "JavaScript heap out of memory" error.

Why this matters

The existing v8js.memory.heap.limit metric (sourced from space_size of getHeapSpaceStatistics()) is the pre-allocated size per space, not the maximum allowed size. This is confusing because:

  1. v8js.memory.heap.limit = sum(space_size) across all spaces = total pre-allocated memory (includes V8 internal overhead, fragmentation). This value changes dynamically as V8 allocates/deallocates pages.
  2. v8.getHeapStatistics().heap_size_limit = the absolute ceiling the heap can grow to. This is a fixed value determined at process startup by --max-old-space-size or V8 defaults.

For alerting on heap memory pressure (e.g., "process is about to OOM"), operators need to know utilization relative to the hard limit, not relative to current pre-allocated size. Currently, the only way to approximate this is heap_used / (heap_used + heap_space_available_size), which measures utilization against currently usable capacity but doesn't tell you how close you are to the absolute ceiling.

Describe the solution you'd like

Add a new metric to the V8 JS engine semantic conventions:

Name Instrument Type Unit Description
v8js.memory.heap.max UpDownCounter By Maximum heap size allowed by the V8 engine.

Source: heap_size_limit from v8.getHeapStatistics()

This is a global value (not per-space), so it would not have the v8js.heap.space.name attribute.

This is analogous to how JVM metrics have jvm.memory.limit (from MemoryPoolMXBean.getMax()) — see JVM memory metrics. A similar gap for JVM was addressed in #519.

Describe alternatives you've considered

  • Using sum(v8js.memory.heap.limit) as a proxy: This sums space_size across all spaces, but space_size is the pre-allocated size (not the max), changes dynamically, and includes internal V8 overhead. It's not the same as heap_size_limit.
  • Using heap_used / (heap_used + heap_space_available_size): This gives utilization against current capacity but doesn't indicate proximity to the hard OOM ceiling.
  • Custom metrics: Vendors like Datadog expose runtime.node.heap.heap_size_limit as a vendor-specific metric, but there's no standard OTel convention for it.

Additional context

The @opentelemetry/instrumentation-runtime-node package in opentelemetry-js-contrib currently only calls v8.getHeapSpaceStatistics() and does not call v8.getHeapStatistics() at all. Once a semantic convention is defined, the instrumentation can be updated to also call getHeapStatistics() and emit this metric.

// v8.getHeapStatistics() returns:
{
  total_heap_size: 6537216,
  total_heap_size_executable: 573440,
  total_physical_size: 5765496,
  total_available_size: 1850337560,
  used_heap_size: 4344600,
  heap_size_limit: 2197815296,  // <-- THIS is the value we need
  malloced_memory: 8192,
  peak_malloced_memory: 587480,
  does_zap_garbage: 0
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Need triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions