The jdk.jcmdmodule​ is a Java module introduced in Java 9 as part of the Java Platform Module System (JPMS). It provides command-line diagnostic and troubleshooting tools for the JVM. This module contains essential tools for monitoring, managing, and debugging Java applications.

Overview of jdk.jcmd Module

The jdk.jcmdmodule includes the following key tools:

jcmd       - JVM Diagnostic Command Utility
jinfo      - Configuration Information
jmap       - Memory Map
jps        - JVM Process Status
jstack     - Stack Trace
jstat      - JVM Statistics Monitoring
jstatd     - jstat Daemon

Detailed Tools Overview

1. jcmd - JVM Diagnostic Command Utility

Most powerful tool in the module. Sends diagnostic command requests to a running JVM.

Basic Usage:

# List all Java processes
jcmd

# List available commands for a specific JVM
jcmd <pid> help

# Get system properties
jcmd <pid> VM.system_properties

# Get thread dump
jcmd <pid> Thread.print

# Heap dump
jcmd <pid> GC.heap_dump <filename>.hprof

# Class histogram
jcmd <pid> GC.class_histogram

Example:

# List all Java processes
$ jcmd
1234 com.example.MyApp
5678 org.example.AnotherApp

# Get thread dump for process 1234
$ jcmd 1234 Thread.print

2. jps - JVM Process Status

Lists instrumented HotSpot Java Virtual Machines (JVMs) on the target system.

Usage:

# Basic listing
jps

# List with main class and arguments
jps -l

# List with JVM arguments
jps -v

# List with main class, arguments, and JVM args
jps -mlv

Output Example:

1234 MyApplication
5678 com.example.Server

3. jstack - Stack Trace

Prints Java thread stack traces for a Java process.

Usage:

# Basic stack trace
jstack <pid>

# Stack trace with locks
jstack -l <pid>

# Force stack dump
jstack -F <pid>

# Output to file
jstack <pid> > thread_dump.txt

4. jmap - Memory Map

Prints shared object memory maps or heap memory details.

Usage:

# Heap summary
jmap -heap <pid>

# Histogram of heap objects
jmap -histo <pid>

# Histogram of live objects only
jmap -histo:live <pid>

# Generate heap dump
jmap -dump:live,format=b,file=heap.hprof <pid>

5. jinfo - Configuration Info

Prints Java configuration information for a given Java process.

Usage:

# Print all system properties and VM flags
jinfo <pid>

# Print specific system property
jinfo -sysprops <pid>

# Print VM flags
jinfo -flags <pid>

# Print command line
jinfo -flag <flag_name> <pid>

6. jstat - JVM Statistics Monitoring

Monitors JVM statistics.

Usage:

# Class loader statistics
jstat -class <pid> 1000 5  # every 1s, 5 times

# Garbage collection statistics
jstat -gc <pid> 1000

# GC capacity statistics
jstat -gccapacity <pid>

# GC utilization statistics
jstat -gcutil <pid> 1000 5

7. jstatd - jstat Daemon

RMI server application that monitors the creation and termination of JVMs.

Usage:

# Start jstatd server
jstatd -J-Djava.security.policy=jstatd.all.policy

# Create policy file (jstatd.all.policy)
grant codebase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};

Practical Examples and Use Cases

Example 1: Comprehensive Application Monitoring Script

#!/bin/bash
# monitor_jvm.sh

PID=$1
OUTPUT_DIR="./diagnostics_$(date +%Y%m%d_%H%M%S)"

mkdir -p $OUTPUT_DIR

echo "=== Collecting JVM Diagnostics for PID: $PID ==="

# 1. Get basic process info
jcmd $PID VM.version > $OUTPUT_DIR/version.txt
jcmd $PID VM.system_properties > $OUTPUT_DIR/properties.txt
jcmd $PID VM.flags > $OUTPUT_DIR/flags.txt

# 2. Get thread dump
jcmd $PID Thread.print > $OUTPUT_DIR/thread_dump.txt

# 3. Get heap histogram
jcmd $PID GC.class_histogram > $OUTPUT_DIR/class_histogram.txt

# 4. Continuous monitoring (5 samples, 2 seconds apart)
for i in {1..5}; do
    echo "Sample $i:" >> $OUTPUT_DIR/jstat_gc.txt
    jstat -gc $PID >> $OUTPUT_DIR/jstat_gc.txt
    echo "" >> $OUTPUT_DIR/jstat_gc.txt
    sleep 2
done

echo "Diagnostics saved to: $OUTPUT_DIR"

Example 2: Java Program Using jcmd Module Programmatically

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class JcmdProgrammaticAccess {
    
    public static void main(String[] args) throws Exception {
        // Get current process ID
        String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
        System.out.println("Current PID: " + pid);
        
        // Example 1: List all Java processes
        System.out.println("\n=== All Java Processes ===");
        List<String> processes = executeCommand("jcmd");
        processes.forEach(System.out::println);
        
        // Example 2: Get VM info for current process
        System.out.println("\n=== VM Version Info ===");
        executeCommand("jcmd", pid, "VM.version").forEach(System.out::println);
        
        // Example 3: Get thread dump
        System.out.println("\n=== Thread Count ===");
        String threadOutput = executeCommand("jcmd", pid, "Thread.print")
            .stream()
            .collect(Collectors.joining("\n"));
        
        long threadCount = Arrays.stream(threadOutput.split("\n"))
            .filter(line -> line.contains("Thread"))
            .count();
        System.out.println("Total threads: " + threadCount);
        
        // Example 4: Monitor GC
        System.out.println("\n=== GC Statistics ===");
        executeCommand("jstat", "-gcutil", pid, "1000", "3")
            .forEach(System.out::println);
    }
    
    private static List<String> executeCommand(String... command) throws Exception {
        ProcessBuilder pb = new ProcessBuilder(command);
        Process process = pb.start();
        
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(process.getInputStream()))) {
            return reader.lines().collect(Collectors.toList());
        }
    }
}

Example 3: Advanced Diagnostics Utility

import java.io.FileWriter;
import java.io.PrintWriter;
import java.lang.management.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class AdvancedJVMDiagnostics {
    
    public static void main(String[] args) throws Exception {
        String pid = args.length > 0 ? args[0] : 
            ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
        
        String timestamp = LocalDateTime.now().format(
            DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
        String outputFile = "jvm_diagnostics_" + timestamp + ".txt";
        
        try (PrintWriter out = new PrintWriter(new FileWriter(outputFile))) {
            out.println("=== JVM Diagnostics Report ===");
            out.println("Generated: " + LocalDateTime.now());
            out.println("PID: " + pid);
            out.println();
            
            // Collect various diagnostics
            collectBasicInfo(out, pid);
            collectThreadInfo(out, pid);
            collectMemoryInfo(out, pid);
            collectGCInfo(out, pid);
            collectClassInfo(out, pid);
            
            System.out.println("Diagnostics report saved to: " + outputFile);
        }
    }
    
    private static void collectBasicInfo(PrintWriter out, String pid) throws Exception {
        out.println("=== BASIC JVM INFORMATION ===");
        executeCommand(out, "jcmd", pid, "VM.version");
        executeCommand(out, "jcmd", pid, "VM.command_line");
        executeCommand(out, "jcmd", pid, "VM.system_properties");
        out.println();
    }
    
    private static void collectThreadInfo(PrintWriter out, String pid) throws Exception {
        out.println("=== THREAD INFORMATION ===");
        executeCommand(out, "jcmd", pid, "Thread.print");
        out.println();
    }
    
    private static void collectMemoryInfo(PrintWriter out, String pid) throws Exception {
        out.println("=== MEMORY INFORMATION ===");
        executeCommand(out, "jcmd", pid, "VM.info");
        executeCommand(out, "jmap", "-heap", pid);
        out.println();
    }
    
    private static void collectGCInfo(PrintWriter out, String pid) throws Exception {
        out.println("=== GARBAGE COLLECTION INFORMATION ===");
        executeCommand(out, "jcmd", pid, "GC.heap_info");
        executeCommand(out, "jstat", "-gcutil", pid);
        out.println();
    }
    
    private static void collectClassInfo(PrintWriter out, String pid) throws Exception {
        out.println("=== CLASS INFORMATION ===");
        executeCommand(out, "jcmd", pid, "GC.class_histogram");
        out.println();
    }
    
    private static void executeCommand(PrintWriter out, String... command) throws Exception {
        ProcessBuilder pb = new ProcessBuilder(command);
        Process process = pb.start();
        
        try (Scanner scanner = new Scanner(process.getInputStream())) {
            while (scanner.hasNextLine()) {
                out.println(scanner.nextLine());
            }
        }
        
        process.waitFor();
    }
}

Module Declaration and Dependencies

module-info.java for using jdk.jcmd:

module my.application {
    requires jdk.jcmd;
    // other module dependencies
}

Common dependencies with jdk.jcmd:

module my.diagnostic.tool {
    requires jdk.jcmd;
    requires jdk.management;      // For JMX access
    requires java.management;    // For MBean access
    // The jdk.jcmd module automatically requires:
    // - java.base
    // - jdk.internal.vm.ci
    // - jdk.management.agent
}

Practical Use Cases

1. Production Debugging

# When application is hanging
jcmd <pid> Thread.print > thread_dump_$(date +%s).txt
jcmd <pid> GC.heap_dump /tmp/heap_$(date +%s).hprof

2. Performance Monitoring

# Monitor GC activity
watch -n 1 "jstat -gc <pid>"

# Monitor class loading
jstat -class <pid> 1000

3. Configuration Validation

# Check JVM flags
jinfo -flags <pid>

# Verify system properties
jinfo -sysprops <pid> | grep important.property

4. Memory Leak Detection

# Take heap dump
jmap -dump:live,format=b,file=heap.hprof <pid>

# Analyze object histogram
jmap -histo:live <pid> | head -20

Security Considerations

  1. Permissions Required:

    • Tools require appropriate OS permissions

    • jstatdrequires security policy configuration

    • Some operations may require the same user as the JVM process

  2. Production Considerations:

    • Heap dumps can be large

    • Some commands are intrusive (stop-the-world)

    • Use with caution on production systems

Comparison Table

Tool

Primary Use

Intrusiveness

Output

jcmd

General diagnostics

Low

Text/Heap dumps

jps

List JVMs

None

Process list

jstack

Thread analysis

Medium

Stack traces

jmap

Memory analysis

High (for dumps)

Heap dumps/Histograms

jinfo

Configuration

Low

Config info

jstat

Statistics

None

Numeric stats

jstatd

Remote monitoring

None

RMI service

Best Practices

  1. Use jcmd over individual tools​ when possible (more consistent)

  2. Schedule heavy operations​ (heap dumps) during off-peak

  3. Redirect output to files​ for analysis

  4. Use live option​ (:live) to avoid unnecessary data

  5. Combine tools​ for comprehensive analysis

  6. Monitor before problems occur​ to establish baselines

Common Troubleshooting Commands

# Find Java process by name
jps -l | grep -i myapp

# Quick health check
jcmd <pid> VM.version && \
jcmd <pid> VM.uptime && \
jcmd <pid> GC.heap_info

# Generate full diagnostic report
jcmd <pid> PerfCounter.print > perf_counters.txt
jcmd <pid> Compiler.codecache > codecache.txt
jcmd <pid> VM.native_memory > native_memory.txt

The jdk.jcmdmodule is essential for Java developers and administrators who need to monitor, debug, and troubleshoot Java applications in production environments. It provides a comprehensive set of tools for understanding JVM behavior and diagnosing performance issues.

 

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐