Performing JVM memory analysis helps identify and resolve potential issues.
By leveraging the built-in tools provided by JDK, you can diagnose possible problems and determine optimization directions.
There are several benefits to JVM memory analysis.
- Memory Leak Detection: A JVM memory leak occurs when objects in an application occupy memory that cannot be reclaimed by the garbage collector, leading to a continuous increase in memory usage and eventually exhausting available memory. Using memory analysis tools, you can detect which objects consume large amounts of memory and are not being released, helping to locate code that may have memory leaks.
- Memory Optimization: Adjusting JVM memory settings can improve application performance and stability. By analyzing memory usage, you can adjust heap size, permanent generation (for older Java versions), and the ratio between young and old generations to reduce garbage collection frequency and memory consumption.
- Performance Tuning: Memory analysis can help identify bottlenecks in memory, such as long pauses caused by frequent Full GCs. Adjusting the garbage collector type, GC algorithm, and heap size can enhance application performance.
- Exception Analysis: When an application encounters memory-related exceptions like OutOfMemoryError, analyzing memory usage can reveal the root cause, such as a module or object consuming excessive memory.
- Capacity Planning: For large-scale applications or systems requiring long-running operations, memory analysis helps plan capacity to ensure sufficient memory resources for normal operation.
This article demonstrates the use of jps, jcmd, jstat, jstack, and jmap tools through a JVM memory analysis process.
The example uses JDK 17.
A JVM Memory Analysis Process
When performing JVM memory analysis, combining jps, jcmd, jstat, jstack, and jmap provides comprehensive diagnostic information.
Here is a typical workflow:
Use jps to find the PID of the Java process:
bash
Code Explanation
Copy Code
jps -l
This command lists all running Java processes along with their PIDs and main class names.
Use jcmd for diagnostic commands:
bash
Code Explanation
Copy Code
jcmd <PID> VM.flags jcmd <PID> VM.system_properties
These commands display JVM startup parameters and system properties, helping to understand the JVM configuration.
Use jstat to monitor JVM memory and garbage collection:
bash
Code Explanation
Copy Code
jstat -gc <PID> 5000 10
This continuously outputs garbage collection statistics, including memory usage in different heap regions and GC times.
Use jstack to generate thread stack information:
bash
Code Explanation
Copy Code
jstack <PID>
This shows thread stack information to check for deadlocks or other thread-related issues.
Use jmap to generate a heap dump file:
bash
Code Explanation
Copy Code
jmap -dump:file=heapdump.hprof <PID>
This generates a heap dump file named heapdump.hprof, which can be used for further analysis of memory usage, such as identifying memory leaks.
Analyze the heap dump file:
Use tools like Eclipse Memory Analyzer (MAT) or VisualVM to analyze the generated heap dump file, looking for memory leaks, large objects, or unused objects.
By using these tools together, you can gain a comprehensive understanding of the JVM runtime state, diagnose performance issues, and resolve memory-related errors.
Below is a detailed explanation of how to use these tools.
jps
jps is a command-line tool provided by the JDK used to list Java Virtual Machine processes. It is typically used to view the PID (process identifier) and corresponding main class name of running Java processes.
You can also use ps -ef|grep java to find the PID.
bash
Code Explanation
Copy Code
jps [ options ] [ hostid ]
Where options are optional parameters and hostid is an optional host identifier. Common options include:
-q: Display only the process ID without the main class name.-m: Show arguments passed to the main class.-l: Display the fully qualified name of the main class, usually used to distinguish specific Java applications.-v: Show arguments passed to the JVM.
For example, to show the PID and main class name of all running Java processes, simply run the jps command:
bash
Code Explanation
Copy Code
jps
To display only the PIDs, use the -q option:
bash
Code Explanation
Copy Code
jps -q
To display the fully qualified name of the main class, use the -l option:
bash
Code Explanation
Copy Code
jps -l
To display arguments passed to the main class, use the -m option:
bash
Code Explanation
Copy Code
jps -m
To display arguments passed to the JVM, use the -v option:
bash
Code Explanation
Copy Code
jps -v
jcmd
jcmd: The jcmd command was introduced in Java 8 and can perform various JVM monitoring and diagnostic tasks. For example, you can use jcmd <pid> VM.flags to view JVM startup parameters or jcmd <pid> Thread.print to print thread stack information.
Here is the basic usage of the jcmd command:
bash
Code Explanation
Copy Code
jcmd <PID | main class> <command> [options]
Where:
<PID | main class>: The PID of the Java process or the main class name. If a PID is provided, it directly operates on the corresponding Java process; if a main class name is provided,jcmdattempts to find a matching Java process and execute the corresponding command.<command>: The diagnostic command to execute.[options]: Optional command parameters.
Common jcmd commands include:
- help: Displays a list of supported commands and brief descriptions of each.
- VM.version: Displays JVM version information.
- VM.flags: Displays JVM startup parameters.
- VM.system_properties: Displays JVM system properties.
- Thread.print: Prints the stack trace of all threads in the Java process.
- GC.run: Performs a garbage collection.
- GC.heap_dump: Generates a Java heap dump file.
For example, to print the thread stack information of a specific Java process, use the following command:
bash
Code Explanation
Copy Code
jcmd <PID> Thread.print
To perform a garbage collection, use the following command:
bash
Code Explanation
Copy Code
jcmd <PID> GC.run
To generate a Java heap dump file, use the following command:
bash
Code Explanation
Copy Code
jcmd <PID> GC.heap_dump <filename>
jstat
jstat: The jstat command allows monitoring of JVM memory and garbage collection. For example, you can use jstat -gc <pid> to view garbage collection statistics or jstat -gcutil <pid> to see memory usage and garbage collection details.
Here is the basic usage of the jstat command:
bash
Code Explanation
Copy Code
jstat [ options ] <PID> [ interval [ count ] ]
Where:
[ options ]: Optional command options specifying the type and format of data to monitor.<PID>: The PID of the Java process to monitor.[ interval ]: An optional parameter specifying the time interval (in milliseconds) for outputting statistical information. If omitted, the default is once per second.[ count ]: An optional parameter specifying the number of times to output statistical information. If omitted, the default is to output indefinitely.
Common jstat command options include:
- -class: Displays class loading, unloading, and class loader status.
- -gc: Displays garbage collection-related information, including memory usage in different generations.
- -compiler: Displays Just-In-Time (JIT) compiler compilation statistics.
- -gccapacity: Displays capacity and usage information for different heap regions.
- -gcutil: Displays memory usage in different heap regions in percentage.
- -gccause: Displays the reason for the last GC.
- -printcompilation: Prints JIT compilation information for methods.
For example, to view class loading information for a Java process, use the following command:
bash
Code Explanation
Copy Code
jstat -class <PID>
If you want to output class loading information every 5 seconds for 10 times, use the following command:
bash
Code Explanation
Copy Code
jstat -class <PID> 5000 10
jstat only displays current GC information. For production environments, it's better to start the JVM with -XX:+PrintGCDetails -Xloggc:/path/to/gc.log (for JDK 1.8 and earlier) or -Xlog:gc*:file=/path/to/gc.log (for JDK 9 and later) to capture GC logs, which can then be analyzed using tools like GCViewer or GCeasy (requires registration).
jstack
jstack: The jstack command is used to generate thread dumps, which can be used to analyze thread states and deadlocks. For example, you can use jstack <pid> to print thread stack information, or jstack -l <pid> to print thread stack information along with lock details.
Here is the basic usage of the jstack command:
bash
Code Explanation
Copy Code
jstack [ options ] <PID>
Where:
[ options ]: Optional command options specifying the output format.<PID>: The PID of the Java process for which to generate thread stack information.
Common jstack command options include:
- -l: Long list format, showing additional information about locks, such as owners and wait queues.
- -F: Forces the generation of thread stack information when the normal
jstackcommand fails. This can be useful when the Java process is unresponsive but may cause a temporary pause. - -m: Displays both Java and native method stack traces, not just Java stack traces.
- -h: Displays help information.
For example, to generate thread stack information for a specific Java process, use the following command:
bash
Code Explanation
Copy Code
jstack <PID>
To output long list format thread stack information, use the -l option:
bash
Code Explanation
Copy Code
jstack -l <PID>
If the Java process is unresponsive, use the -F option to force the generation of thread stack information:
bash
Code Explanation
Copy Code
jstack -F <PID>
jmap
When an exception occurs and it is difficult to locate the problematic code, you can use jmap to generate a dump file.
Then, import it into MAT for analysis. Here are the steps to generate a heap dump file:
- Identify the Java process ID: First, determine the PID of the running Java process. You can use the
jpscommand to view running Java processes and their PIDs. - Generate a heap dump file: Use the
jmapcommand to generate a heap dump file. The command format is as follows:
shell
Code Explanation
Copy Code
jmap -dump:file=<file path> <PID>
For example, to generate a heap dump file named heapdump.hprof, run the following command:
shell
Code Explanation
Copy Code
jmap -dump:file=heapdump.hprof <PID>
This will create a heapdump.hprof file in the current working directoyr.
- Import the heap dump file into MAT: Open MAT and select
File -> Open Heap Dump, then choose the generated heap dump file. - Perform memory analysis: Once the heap dump file is imported into MAT, you can perform memory analysis according to the steps outlined above.
These steps allow you to manually generate a heap dump file and analyze it with MAT, evenif no heap dump was generated automatically during an OutOfMemoryError.
In production environments, it's better to add the -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof parameter when starting the JVM so that a heap dump is automatically generated when an OutOfMemoryError occurs.