A Java crash can be a nightmare for developers. The dreaded Java Virtual Machine (JVM) crashes are quite common, and if you are a Java developer, you would probably know how difficult it is to diagnose and recover from a crash.
It is inevitable to avoid Java crashes fully, but this article will provide you with a complete guide to diagnose a Java crash, find its root cause and how you can prevent it from reoccurring.
1. Classify the JVM crashes
The first question is, where can you even start diagnosing a Java crash? You need to know why it crashed, and what JVM was doing at the time it crashed. When the JVM crashes, a snapshot of the current state of the computer and the JVM process at the time of the crash is saved in the form of two crash files.
Following the crash, files are very functional for the classification of the JVM crashes, making it easier to identify the reason behind the crash and diagnose them:
It is a text file that contains a complete summary of the memory image and the environment in which the JVM was running at the time of the crash. JVM produces this file itself when it crashes and proves extremely useful for classifying the Java crashes. It indicates that the JVM process has run out-of-virtual memory, and stack overflow errors are also mentioned.
.core file/.mdmp file
.core is a binary crash file produced on UNIX-based systems such as Linux and Solaris. By default, the .core file captures the complete information about the entire JVM process when it was crashed.
.mdmp file or minidump file is the Windows equivalent for the .core in the Linux-based systems. The size of the .core file (or .mdmp) file is close to the maximum virtual memory of the process on the operating system that comes in very handy when verifying the out-of-virtual-memory crash.
2. Types of Java crashes and how to diagnose them
· Out-of-virtual-memory crash
The JVM reserves virtual memory for various reasons: the Java heap, Java methods, thread stacks, and JVM-internal data structures. All that allocated memory is assigned to the respective process as per the requirements while keeping the operating system limitations in check.
Suppose the virtual memory allocation of the JVM process exceeds the operating system limitations due to any reason. In that case, the JVM will run out of virtual memory, resulting in JVM crashing.
· Verify the out-of-virtual-memory error
The first thing to do is check the maximum virtual memory available to a single process by your operating system. Almost every 32-bit operating system offers 2GB to 3GB of virtual memory, whereas it is practically unlimited on 64-bit platforms.
So, if you are using a 64-bit operating system, then it is very much unlikely that JVM would have crashed due to an out-of-virtual-memory error.
Still, on a 32-bit system, you can verify if an out-of-virtual-memory error has occurred in the following ways:
· Look in the text crash file (.dump file).
It is mentioned in the text crash file .dump if JVM has failed in memory allocation. This is a strong indication that a JVM process must have run out of virtual memory.
· Check the size of the binary crash file.
The binary crash file (.core or .mdmp), by default, contains a copy of the entire JVM process. You can check the size of the binary crash file to verify whether the JVM process has indeed run out of virtual memory or not. If the size of the binary crash file is larger than the size of the memory heap, this will ensure that the binary crash file has not been cut short due to limited disk space.
Troubleshooting the out-of-virtual-memory error
After verifying that the JVM process has indeed run out of virtual memory, you can troubleshoot the problem using the following ways:
· Upgrade to the latest JVM release
Always use the latest JVM release so that any problem causing the JVM crashes might have been fixed in the latest JVM release.
· Reduce the Java heap size
The Java heap is only a certain part of the total memory used by the JVM. If the Java heap is significantly larger, JVM can run out of virtual memory while compiling methods or when native libraries are loaded. Try lowering the maximum heap size to avoid this error.
· Use the Windows 3GB startup option
On almost every Windows version, users can start the operating system with the /3GB option. This will upgrade the maximum virtual memory process size from 2 GB to 3 GB.
· Remove, if any memory leaks in your JNI code
Properly test the JNI code for any memory leaks. An inefficient or poorly written JNI code can result in memory leaks, which will result in the Java process growing until it reaches the maximum virtual memory size on the platform and eventually crashing.
4. JVM crash due to stack overflow
The infamous stack overflow crash occurs when the JVM is unsuccessful in handling a stack overflow error. A proper way of handling the Java.lang.StackOverflowError is when a java.lang.VirtualMachineError is thrown to indicate to the developer that JVM has crashed or has run out of resources required to continue the operation. Still, in an unsuccessful attempt, JVM could crash abruptly.
In that crash, The JVM .dump file can verify the error as it includes the information about the number of stack overflow errors thrown.
· Verify the stack overflow crash
It is very simple to verify that the crash is due to the stack overflow error as the text crash file (.dump) shows Error Message: Stack overflow near the top of the file when the JVM crashes due to stack overflow.
· Troubleshooting a stack overflow crash
Following are the possible solutions for handling Java crashes due to stack overflow errors.
· Application-level changes
In most cases, a stack overflow error is caused by an application requiring a lot of stack space that eventually exceeds the memory limits of the JVM. You can examine the stack trace in the .dump file.
To prevent it, you can optimize the Java code to use lesser stack space. For example, the application might consist of recursive method calls or deep recursions that cause stack overflow errors. These should be replaced with another logic to prevent the stack overflow error.
· Increase the default stack size
If it is not suitable to change the stack requirements of the application, you can change the size limit of the stack by using the -Xss command-line option.
5. JVM crash due to a programming error
A JVM crash could also be caused due to a programming error or an error in third-party library code.
Troubleshooting the JVM crash due to code generation
The Following are the ways to identify and troubleshoot a JVM crash during code generation.
· Identify the method that might have caused the JVM crash
If Java crashes while generating a code, the most common reason could be an error during method compilation. If the JVM does not properly compile a method, either the JVM crashes or the method gets compiled, resulting in a logical error.
· Verify if the crash is because of optimization problems
The JVM can produce an error in method compilation due to a problem in the optimizing compiler. To confirm if the optimization is the reason for the crash, you can disable the optimization by specifying the -XnoOpt command-line option and then restart the application, as shown below:
java -XnoOpt myApplication
If the JVM runs the application as expected, code optimization is the reason behind the crash.
· Exclude the suspect method from the optimization process
The JVM might not compile a method due to a problem in the optimizing compiler. You should first disable the code optimization. If the JVM still crashes after you have disabled the global optimization, you can easily exclude the offending methods identified earlier. If the application starts to run without the suspected method being optimized, this workaround should solve your problem.
6. JVM crash due to garbage collection error
Garbage collection is another very significant reason behind Java crashes. You can identify a garbage collection crash by analyzing the stack trace in the text crash file (.dump). If the garbage collection functions are shown in the stack trace or if the crash causing thread is a garbage collection thread, the crash must have occurred during the garbage collection. You can easily identify the garbage collection functions in the stack trace by the prefixes like mm, gc, yc, and oc.
See Also: Encapsulation In Java With Example
This article contains some smart tips and tricks for diagnosing Java crashes. Anyone working with Java applications would be well-aware that JVM crashes can cause widespread outages and can be extremely time-consuming to diagnose. While many of these problems are mysteries that remain unsolved, all it takes is some smart use of your Java knowledge and some persistence in troubleshooting and solving these errors.