# Debugging Java Applications from the Command Line: Essential JVM Diagnostics

> Easily debug Java applications from the command line. Use `jstack`, `jmap`, and `jstat` to capture vital JVM diagnostics like thread dumps and heap snapshots without an IDE.

- Repository: [Joshua Levy/the-art-of-command-line](https://github.com/jlevy/the-art-of-command-line)
- Tags: how-to-guide
- Published: 2026-02-24

---

**Send a SIGQUIT signal with `kill -3` or use JDK tools like `jstack`, `jmap`, and `jstat` to capture thread dumps, heap snapshots, and GC statistics without attaching an IDE debugger.**

When production Java services hang, leak memory, or spike CPU, attaching a graphical debugger is rarely feasible. According to the `jlevy/the-art-of-command-line` repository, debugging Java applications from the command line offers lightweight, scriptable alternatives that require zero code changes and work on any headless server.

## Core JDK Diagnostic Tools

The Java Development Kit (JDK) ships with several command-line utilities that attach to running JVMs to extract diagnostic data. As documented in the repository's [`README.md`](https://github.com/jlevy/the-art-of-command-line/blob/main/README.md) in the "System debugging" section around line 324, these tools form the foundation of production troubleshooting workflows.

### Generating Thread Dumps with SIGQUIT and jstack

The fastest way to inspect a frozen JVM is sending a **SIGQUIT** signal using `kill -3 <pid>`. This causes the JVM to print a full thread dump (stack trace for every thread) and a heap summary to **stderr** or the application's log file without terminating the process.

For on-demand capture to a file, use **jstack**:

```bash
jstack 12345 > thread_dump_$(date +%s).txt

```

Both methods produce identical stack traces, but `jstack` routes output to stdout for immediate piping, while `kill -3` writes to the process's configured log destination.

### Capturing Heap Snapshots with jmap

To diagnose memory leaks, **jmap** dumps the live heap of a running JVM into a binary format suitable for offline analysis with Eclipse MAT or VisualVM:

```bash
jmap -dump:live,format=b,file=heap_$(date +%s).hprof 12345

```

The `live` flag triggers a full GC before dumping, ensuring only reachable objects are captured. This binary file can be transferred to a workstation for detailed object graph analysis.

### Real-Time Monitoring with jstat

For performance tuning, **jstat** provides real-time statistics about garbage collection, class loading, and compiler usage without stopping the application:

```bash
jstat -gc 12345 1000 10

```

This samples GC activity every 1000 milliseconds for 10 iterations, printing metrics like Eden space utilization, survivor counts, and old generation occupancy directly to the terminal.

### Identifying Target Processes with jps

Before attaching any diagnostic tool, locate your application's **PID** using **jps** (Java Process Status):

```bash
jps -l

```

The `-l` flag displays the full package name or JAR path for each Java process, making it easy to distinguish between multiple running JVMs when filtering with `grep` or `awk`.

## Advanced Utilities and SJK Tools

Beyond the standard JDK distribution, the **SJK (Swiss Java Knife)** tools provide enhanced wrappers around `jps`, `jstack`, `jmap`, and `jstat` with additional filtering and formatting options. If installed, SJK offers convenient one-liners for common tasks:

```bash
sjk jstack 12345

```

These utilities are particularly valuable when standard tools are unavailable or when you need aggregated views across multiple JVM instances.

## Practical Debugging Workflows

Combine these utilities into shell functions for automated incident response. The following sequence demonstrates a complete diagnostic capture for a hypothetical application named `MyApp`:

```bash

# 1. Resolve the PID dynamically

PID=$(jps -l | grep MyApp | awk '{print $1}')

# 2. Capture thread dump to timestamped file

jstack "$PID" > /tmp/thread_dump_$(date +%s).txt

# 3. Trigger JVM-native thread dump to logs via SIGQUIT

kill -3 "$PID"

# 4. Extract binary heap dump for offline analysis

jmap -dump:live,format=b,file=/tmp/heap_$(date +%s).hprof "$PID"

# 5. Monitor GC pressure in real time

jstat -gc "$PID" 1000 10

```

These commands are lightweight, require no application restarts, and can be triggered via cron jobs or monitoring hooks to capture periodic snapshots during suspected instability.

## Summary

- **`kill -3 <pid>`** sends SIGQUIT to force the JVM to print thread dumps and heap summaries to stderr or log files.
- **`jps -l`** lists running Java processes with their main class or JAR names to identify target PIDs.
- **`jstack <pid>`** generates on-demand thread dumps sent to stdout for immediate inspection or file redirection.
- **`jmap -dump:live,format=b,file=...`** creates binary heap snapshots for offline memory analysis tools.
- **`jstat -gc`** provides real-time garbage collection and memory pool statistics without pausing the application.
- All techniques documented in `jlevy/the-art-of-command-line` work on headless servers and require no code modifications or IDE attachments.

## Frequently Asked Questions

### What is the difference between `kill -3` and `jstack`?

Both generate identical thread dumps, but `kill -3` sends a **SIGQUIT** signal that the JVM handles internally by writing to its stderr or configured log file, while `jstack` connects to the process and prints the stack trace to the invoking shell's stdout, allowing immediate capture to files or pipes.

### How do I analyze a binary heap dump created with `jmap`?

Import the `.hprof` or `.bin` file generated by `jmap -dump` into the **Eclipse Memory Analyzer Tool (MAT)** or **VisualVM**. These applications parse the object graph to identify leak suspects, dominator trees, and retained heap sizes without requiring access to the original running JVM.

### Can these debugging tools be used on production servers without stopping the application?

Yes. `jstack`, `jstat`, and `kill -3` attach to the running process and do not require a restart or code changes. Note that `jmap -dump` may cause a brief pause (stop-the-world event) during heap enumeration, so it should be used cautiously on latency-sensitive production workloads.

### Where can I find the authoritative list of these Java debugging techniques?

The definitive reference resides in the `jlevy/the-art-of-command-line` repository, specifically within the **System debugging** section of [`README.md`](https://github.com/jlevy/the-art-of-command-line/blob/main/README.md) around line 324, which catalogs these JDK utilities alongside other platform-agnostic command-line diagnostics.