commontoolsinc

deno-memory-profiler

Analyze memory in a running Deno process via the V8 inspector CDP protocol. Use when the user asks about memory usage, memory leaks, heap analysis, heap snapshots, allocation profiling, or object retention in a Deno process running with --inspect.

commontoolsinc 55 13 Updated 5mo ago

Resources

1
GitHub

Install

npx skillscat add commontoolsinc/labs/deno-memory-profiler

Install via the SkillsCat registry.

SKILL.md

Deno Memory Profiler

Analyze memory in a running Deno process via the V8 inspector CDP protocol.

When to use

Use this skill when the user asks about:

  • Memory usage of a running Deno process
  • Memory leaks or growing heap
  • Heap analysis or heap snapshots
  • Allocation profiling
  • Object retention or constructor counts

The target Deno process must be running with --inspect or --inspect-brk.
The default inspector port is 9229.

Prerequisites

The target process must be started with the inspect flag:

deno run --inspect main.ts          # default port 9229
deno run --inspect=0.0.0.0:9230 main.ts  # custom host/port

Available commands

The script is at skills/deno-memory-profiler/scripts/memory.ts. When
run_skill_script is available and exactly allowlisted, invoke it with
skill="deno-memory-profiler" and path="scripts/memory.ts" instead of
constructing a shell command.

All commands accept --port=<port> (default 9229) and --host=<host> (default
127.0.0.1). Output is JSON to stdout; status messages go to stderr.

usage — Quick heap stats

deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts usage
deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts usage --gc

Returns usedSize, totalSize, usagePercent. Use --gc to force garbage
collection before measuring for a more accurate picture.

eval <expression> — Evaluate in target process

deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts eval "Deno.memoryUsage()"
deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts eval "globalThis.myCache.size"

Runs an expression in the target via Runtime.evaluate and prints the result.
Useful for inspecting specific objects.

sample — Allocation sampling

deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts sample --duration 10
deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts sample --duration 5 --top 50 --interval 16384

Profiles allocations for the given duration. Returns the top allocation sites
sorted by bytes allocated. Options:

  • --duration <seconds> — sampling time (default 5)
  • --top <N> — number of sites to show (default 30)
  • --interval <bytes> — sampling interval (default 32768; lower = more detail,
    more overhead)

snapshot — Full heap snapshot summary

deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts snapshot

Takes a V8 heap snapshot and produces a summary: total size, top 20 constructors
by shallow size, top 10 by instance count, and duplicate strings (>50
occurrences).

diff baseline / diff compare — Leak detection

# Phase 1: capture baseline
deno run --allow-net --allow-write skills/deno-memory-profiler/scripts/memory.ts diff baseline

# ... user triggers suspected leaky operation ...

# Phase 2: compare
deno run --allow-net --allow-read skills/deno-memory-profiler/scripts/memory.ts diff compare

Two-phase leak detection. Baseline saves a snapshot summary to
/tmp/memory-baseline-{port}.json. Compare takes a new snapshot and reports:

  • Total heap growth (bytes and percent)
  • New constructors not in baseline
  • Constructors with increased instance count or size
  • Constructors that disappeared

Workflow examples

Quick health check

deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts usage --gc

Get the current heap state after GC. Good first step to see if memory is
unexpectedly high.

Allocation profiling

deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts sample --duration 10

Run this while the user triggers their workload. Shows where allocations are
happening — useful for finding hot allocation paths.

Leak detection

# 1. Take baseline while idle
deno run --allow-net --allow-write skills/deno-memory-profiler/scripts/memory.ts diff baseline

# 2. Ask user to trigger the suspected leaky operation several times

# 3. Compare
deno run --allow-net --allow-read skills/deno-memory-profiler/scripts/memory.ts diff compare

The diff shows what grew. Focus on constructors with large deltaCount or
deltaSize.

Deep inspection

# Full snapshot breakdown
deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts snapshot

# Then poke at specific objects
deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts eval "Deno.memoryUsage()"
deno run --allow-net skills/deno-memory-profiler/scripts/memory.ts eval "globalThis.myMap?.size"

Interpreting results

  • Large shallow size with high count: Usually arrays, buffers, or string
    data being retained. Look at what constructor owns them and trace back to why
    they're kept alive.
  • Growing constructors between baseline and compare: These are likely leaks
    — objects being created but not released. Focus on the ones with the highest
    deltaCount.
  • High allocation count in sampling: Hot allocation paths that may benefit
    from object pooling, caching, or restructuring to reduce GC pressure.
  • Duplicate strings: Many identical strings suggest opportunities for string
    interning or indicates a pattern creating redundant string copies.
  • New constructors in diff compare: Types that didn't exist at baseline may
    indicate new subsystems being loaded, or leaked closures/objects from the
    triggered operation.

Limitations

  • Snapshot size: Snapshot parsing can be slow and memory-intensive for very
    large heaps (>500MB). The profiler process itself needs memory to parse the
    JSON.
  • Sampling is duration-based: Coordinate with the user on timing — the
    sampling period should overlap with the workload being profiled.
  • No retained size: Computing retained size requires building a dominator
    tree, which is expensive. Shallow size grouped by constructor is provided
    instead, which is still very useful for identifying leaks and large
    allocations.
  • Single target: Connects to the first debuggable target. If multiple
    isolates are running, only the first is profiled.
  • Inspector must be enabled: The target process must be running with
    --inspect. There's no way to attach to a process that wasn't started with
    this flag.