async-profiler - Low-Overhead JVM Profiler Cheatsheet
async-profiler is a low-overhead sampling profiler for the JVM. Traditional Java profilers sample only at safepoints, which biases results toward whatever code happens to sit near a safepoint and can hide the real hot path. async-profiler uses AsyncGetCallTrace plus perf events to sample anywhere, including native code and kernel frames, giving a far more honest picture. It profiles CPU, allocations, lock contention, and more, and exports flame graphs or JFR.
Installation
| Method | How |
|---|
| Download | Get the release tarball for your platform |
| Extract | tar xzf async-profiler-*.tar.gz |
| Run | ./bin/asprof <pid> (newer) or ./profiler.sh <pid> |
| Permissions | may need sysctl kernel.perf_event_paranoid=1 and kernel.kptr_restrict=0 |
| Verify | ./bin/asprof --version |
Basic Profiling
| Command | Description |
|---|
asprof -d 30 -f out.html <pid> | Profile 30s → flame graph |
asprof -e alloc -d 30 -f alloc.html <pid> | Allocation profiling |
asprof -e lock -d 30 -f lock.html <pid> | Lock contention |
asprof -e wall -d 30 -f wall.html <pid> | Wall-clock (includes waiting) |
asprof start <pid> / asprof stop -f out.html <pid> | Manual start/stop |
jps | Find the JVM pid |
Event Types
| Event | Measures |
|---|
cpu | CPU time (default) |
alloc | Heap allocations by stack |
lock | Lock/monitor contention |
wall | Wall-clock including blocked time |
itimer | Fallback when perf is unavailable |
cache-misses, page-faults | Hardware/software perf events |
# Where is the app actually spending wall-clock time (incl. IO waits)?
./bin/asprof -e wall -t -d 30 -f wall.html <pid>
| Flag | Produces |
|---|
-f out.html | Interactive flame graph |
-o collapsed | Folded stacks (for FlameGraph tooling) |
-o tree | Call tree |
-o flat | Flat hot-method list |
-f out.jfr | JFR recording (open in JMC) |
-t | Split by thread |
Launching With the Agent
# Profile from JVM startup (captures warmup)
java -agentpath:/path/libasyncProfiler.so=start,event=cpu,file=profile.html \
-jar app.jar
| Agent option | Purpose |
|---|
start | Begin immediately |
event=cpu|alloc|lock | What to sample |
file=NAME | Output path |
interval=10ms | Sampling interval |
jfr | Emit JFR format |
Reading the Flame Graph
| Feature | Meaning |
|---|
| Width | Share of samples (time) — wider is hotter |
| Height | Stack depth, not cost |
| Colors | Java (green), native (yellow-ish), kernel (orange) |
| Click | Zoom into a subtree |
| Search | Highlight matching frames |
Look for wide plateaus — a single frame consuming a large horizontal share is your hot spot. Mixed Java/native/kernel frames are exactly what safepoint-biased profilers hide.
Common Workflows
# 1) CPU hotspots in a running service
./bin/asprof -d 60 -f cpu.html $(jps | grep MyApp | cut -d' ' -f1)
# 2) Chasing GC pressure — who allocates most?
./bin/asprof -e alloc -d 60 -f alloc.html <pid>
# 3) Threads look idle but latency is high → wall-clock
./bin/asprof -e wall -t -d 30 -f wall.html <pid>
# 4) Contention on a shared resource
./bin/asprof -e lock -d 30 -f lock.html <pid>
async-profiler vs Alternatives
| Aspect | async-profiler | JFR | VisualVM |
|---|
| Safepoint bias | Avoided | Reduced | Present |
| Native/kernel frames | Yes | Limited | No |
| Overhead | Very low | Low | Higher |
| Allocation profiling | Yes | Yes | Basic |
| Best for | Accurate JVM hotspots | Built-in continuous recording | Quick GUI inspection |
The JVM counterpart to perf + FlameGraph for native code.
Resources