Official Documentation

Heap Hunter End-User Guide

Everything you need to index, inspect, and diagnose Java heap dumps with Heap Hunter.

This guide assumes you have a pre-built hunt binary and a Java .hprof heap dump.


# 1. Files You Need in Your Working Directory

hunt looks for two files in the directory where you run it:

FilePurpose
license.datSigned license file
state.datSupporting anchor for license file

If either is missing, every command (except --help / --version) exits with a license error.

You should receive these from whoever provided the binary. If you are evaluating the project, copies exist in the repository under Licencing/tester/.


# macOS Gatekeeper Note

If you downloaded a prebuilt hunt binary (for example, hunt-aarch64-macos) on macOS, Gatekeeper may refuse to run it and report operation not permitted. This happens because downloaded executables are tagged with the com.apple.quarantine extended attribute, which the kernel enforces even for valid, ad-hoc signed Mach-O binaries.

Remove the quarantine flag:

bash
xattr -d com.apple.quarantine /path/to/hunt

Then run the binary normally:

bash
/path/to/hunt --help

# 2. Getting Help

bash
# Top-level help
hunt --help

# Per-command help
hunt index --help
hunt histogram --help
hunt roots --help

The built-in help shows usage, options, examples, and exit codes for each command.


# 3. Optional: Create a Config File

To avoid typing --index-dir every time, create ~/.config/hunt/config.json:

bash
mkdir -p ~/.config/hunt
cat > ~/.config/hunt/config.json <<'EOF'
{
  "index-dir": "/path/to/your/indexes",
  "memory-budget-mb": 4096
}
EOF

# Config behavior

FieldMeaning
index-dirFor index/overview, this is a base directory.
memory-budget-mbsorting budget and should not be changed

Override the config path with --config /path/to/config.json, or override just the index dir with --index-dir <dir>.


# 4. The Standard Workflow

Heap Hunter is a two-pass tool:

  1. index — scan the .hprof once and write persistent index files.
  2. overview — build a small overview.bin cache for fast summary queries.
  3. Query commands — read from the index/cache.

You must run index, then overview, before any query.

# 4.1 Index the dump

bash
hunt index path/to/heap.hprof --index-dir path/to/heap.idx

On success it prints a JSON summary:

json
{"status":"complete","index_dir":"path/to/heap.idx","n_objects":170877,"n_classes":1844,"n_edges":262839,"n_roots":1851,...}

If an up-to-date index already exists, it prints:

json
{"status":"reused","index_dir":"path/to/heap.idx"}
OptionMeaning
--index-dir <dir>Where to write the index
--memory-budget-mb <n>RAM budget for sorting (default 4096)
--forceRebuild even if a matching index exists
--no-progressSuppress progress spinner

# 4.2 Build the overview cache

bash
hunt overview path/to/heap.hprof --index-dir path/to/heap.idx

This creates overview.bin inside the index directory.

Run it again after re-indexing, or use --force to overwrite.


# 5. Summary Commands (use overview.bin)

# info — high-level dump summary

bash
hunt info --index-dir path/to/heap.idx

Sample output:

text
Header:
  id_size:    8 bytes
  timestamp:  1783429843270

Summary:
  total objects:  169033
  classloaders:   4
  classes:        1844
  arrays:         67091
  heap bytes:     10137438

# histogram — top classes by shallow heap

bash
# CSV output, top 15 by bytes
hunt histogram --index-dir path/to/heap.idx

# Human-readable table
hunt histogram --index-dir path/to/heap.idx --view

# Sort by instance count
hunt histogram --index-dir path/to/heap.idx --view -s

# Limit to 20
hunt histogram --index-dir path/to/heap.idx --view -l 20

Output columns: class, instances, shallow_bytes.

OptionMeaning
-l N, --limit NTop N rows (default 15)
--viewFormatted table instead of CSV
-s, --sort-instancesSort by instance count, not bytes
--match <regex>Include only matching class names
--exclude <regex>Omit matching class names
--min-bytes <n>Minimum total shallow bytes
--min-instances <n>Minimum instance count

Regex notes: supports ^, $, ., *, +, ?, escaped literals, and character classes.

# classes — loaded class metadata

bash
hunt classes --index-dir path/to/heap.idx --view

Output columns: class, superclass, instance_size.

OptionMeaning
--match <regex>Filter class names
--exclude <regex>Exclude class names
--min-instance-size <n>Minimum bytes per instance

# 6. Object Query Commands (use the persistent index)

# objects — list object IDs by class

bash
hunt objects 'com.example.heapforge.User' --index-dir path/to/heap.idx --limit 10

Output is JSON:

json
{
  "pattern": "com.example.heapforge.User",
  "limit": 10,
  "offset": 0,
  "items": [
    {"id": "0x0000000708827488", "ordinal": 4001, "class": "com/example/heapforge/User", "kind": "instance", "shallow_bytes": 85}
  ],
  "next_offset": 1
}
OptionMeaning
--limit NMax objects (default 100)
--offset NSkip first N matches
--reverseDescending ordinal order

# sample — decoded representative objects

bash
hunt sample 'com.example.heapforge.User' --index-dir path/to/heap.idx --limit 3

Returns the same objects as objects, but with field names and values:

json
{
  "items": [{
    "id": "0x0000000708827488",
    "class": "com/example/heapforge/User",
    "shallow_bytes": 85,
    "fields": [
      {"name": "id", "value": 1756},
      {"name": "name", "ref": "0x...", "ordinal": 3998, "class": "java/lang/String"},
      {"name": "active", "value": true}
    ]
  }]
}

# object — decode one object by ID

bash
hunt object 0x0000000708827488 --index-dir path/to/heap.idx

# 7. Reference-Tracing Commands

These commands walk the heap graph built during indexing.

# refs-from — outgoing references

bash
hunt refs-from 0x0000000708827488 --index-dir path/to/heap.idx --limit 10

Sample:

json
{
  "object": "0x0000000708827488",
  "direction": "outbound",
  "items": [
    {"id": "0x...", "ordinal": 3998, "class": "java/lang/String", "relation": "name"}
  ],
  "next_offset": 5
}

# refs-to — incoming references

bash
hunt refs-to 0x0000000708827488 --index-dir path/to/heap.idx --limit 10

Use this to answer "who is holding this object alive?"

# roots — shortest path to a GC root

bash
hunt roots 0x0000000708827488 --index-dir path/to/heap.idx --max-visited 10000

This is the classic leak-analysis command. It performs a breadth-first search back to the nearest GC root and prints the path:

json
{
  "found": true,
  "truncated": false,
  "path": [
    {"id": null, "ordinal": 170877, "class": "virtual root"},
    {"id": "0x...", "class": "com/example/heapforge/UserRepository"},
    {"id": "0x...", "class": "java/util/concurrent/ConcurrentHashMap"},
    {"id": "0x...", "class": "com/example/heapforge/User"}
  ]
}
OptionMeaning
--max-visited <n>Cap BFS node visits

# tree — bounded expansion

bash
# Outbound tree
hunt tree 0x0000000708827488 --index-dir path/to/heap.idx --direction from --depth 3 --max-nodes 50

# Inbound tree
hunt tree 0x0000000708827488 --index-dir path/to/heap.idx --direction to --depth 3 --max-nodes 50
OptionMeaning
`--direction from\to`Follow outbound or inbound refs (default from)
--depth <n>Max depth
--max-nodes <n>Max nodes in output

# 8. Complete Example Session

bash
# 1. Place heap dump file
#copy heap dump to the location where binary and license and state files exist

# 2. Index
hunt index production-heap.hprof --index-dir production-heap.idx

# 3. Overview
hunt overview production-heap.hprof --index-dir production-heap.idx

# 4. Summarize
hunt info --index-dir production-heap.idx
hunt histogram --index-dir production-heap.idx --view -l 20

# 5. Find suspicious class
hunt histogram --index-dir production-heap.idx --match '^com\.mycompany\.' --view -l 10

# 6. Sample instances
hunt sample 'com.mycompany.SessionContext' --index-dir production-heap.idx --limit 3

# 7. Pick an object and trace it
ID=$(hunt objects 'com.mycompany.SessionContext' --index-dir production-heap.idx --limit 1 | python3 -c "import sys,json; print(json.load(sys.stdin)['items'][0]['id'])")
hunt roots "$ID" --index-dir production-heap.idx --max-visited 50000
hunt tree "$ID" --index-dir production-heap.idx --direction to --depth 4 --max-nodes 100

# 9. Output Formats

CommandDefaultWith --view
index, overviewJSON—
infoHuman table—
histogram, classesCSVHuman table
objects, sample, objectJSON—
refs-from, refs-to, roots, treeJSON—

# 10. Environment Variables

VariableEffect
NO_COLOR=1Disable colored output
FORCE_COLOR=1Force colored output even when not a TTY
XDGCONFIGHOMEChanges default config search path

# 11. Common Errors

ErrorCauseFix
license file not foundlicense.dat missing in cwdCopy license file into cwd
state file is corruptstate.dat missing / tamperedCopy valid state.dat into cwd
overview cache not found; run 'hunt overview ...'Querying before overviewRun overview after index
index not found; run 'hunt index ...'Missing or wrong --index-dirCheck path, run index first
object id not found in indexID does not exist or wrong formatUse IDs returned by objects

# 12. Quick Command Reference

CommandWhat it doesNeeds
index <dump>Build persistent indexlicense.dat, state.dat
overview <dump>Build overview.bin cacheExisting index
infoDump summaryOverview cache
histogramClass usage by size/countOverview cache
classesClass metadataOverview cache
objects <regex>Object IDs by classIndex
sample <regex>Decoded object samplesIndex
object <id>Single object decodeIndex
refs-from <id>Outbound refsIndex
refs-to <id>Inbound refsIndex
roots <id>Shortest path to GC rootIndex
tree <id>Bounded ref treeIndex

Ready to try Heap Hunter?

Join the waitlist