A heap histogram counts objects by class, while a heap dump records object state and references needed to investigate why particular objects remain reachable.
Java heap diagnostics: retained objects, histograms and a controlled dump
Java 21+. The program uses JDK classes and requires no preview flags.
Capture a JVM you own
The fixture retains fifty receipt entries through one static list. Each entry owns a small byte array. The static field is an identifiable retention path; an increasing allocation count alone would not explain why an object survives collection.
Run the downloaded diagnostic script against the fixture it starts, rather than attaching to an arbitrary application PID. It collects a live histogram and heap dump using that same JDK’s jcmd, verifies the fixture’s entry count, then stops the fixture and removes its temporary dump. No user process or application secret is inspected.
A histogram can reveal a class growing between captures, but it does not show which reference keeps a particular instance alive. A dump and reference-path analysis answer that second question. The object’s shallow byte count is also different from the memory retained by the reachable subgraph behind it.
Separate the leak hypothesis from evidence
Fifty intentionally retained entries are not a leak. To diagnose a leak, relate retained state to the application’s intended lifetime, compare captures after comparable work, and identify a path that should have been released. A cache without an eviction policy is one candidate; a live queue carrying unfinished work can be legitimate.
Working program
import java.util.*;
import java.util.concurrent.*;
public class RetainedReceiptFixture {
static final List<Entry> retained=new ArrayList<>();
static final class Entry {final byte[] payload=new byte[1024];}
public static void main(String[] args)throws Exception{
for(int i=0;i<50;i++)retained.add(new Entry());
System.out.println("retained="+retained.size());
if(args.length==1&&args[0].equals("--inspect")){
System.out.println("ready");System.out.flush();new CountDownLatch(1).await(30,TimeUnit.SECONDS);
}
}
}Output
retained=50Costs and boundaries
This fixture retains fifty entries plus their payloads. A histogram or dump can trigger substantial work and pauses; capture it only under an approved operational procedure for a real service. The bundled check covers controlled capture, not a complete graphical retained-size investigation or a production incident.
Common Mistakes
- Allocated bytes and currently retained bytes are different measurements.
- A histogram does not expose every retaining reference path.
- Heap dumps can contain application data; the fixture contains only synthetic bytes.
