According to the Java Language Specification, §11.1.1, "The Kinds of Exceptions" [JLS 2011],
The unchecked exceptions classes are the class
RuntimeExceptionand its subclasses, and the classErrorand its subclasses. All other exception classes are checked exception classes.
Unchecked exception classes such as Error and its subclasses are not subject to compile-time checking not only because it is tedious to account for all exceptional conditions, but also because recovery is generally difficult. However, even when recovery is impossible, the Java Virtual Machine (JVM) allows a graceful exit and a chance to at least log the error. This is made possible by using a try-catch block that catches Throwable. Also, when code must avoid leaking potentially sensitive information, catching Throwable is permitted. In all other cases, catching Throwable is not recommended. Where cleanup operations such as releasing system resources are possible, code should use a finally block within which the resources are released or should use a try-with-resources statement.
Catching Throwable is forbidden by rule ERR08-J. Do not catch NullPointerException or any of its ancestors, but is permitted when filtering exceptions by the exception ERR08-EX0 in that rule.
This noncompliant code example generates a StackOverflowError as a result of infinite recursion. It exhausts the available stack space and may result in denial of service.
public class StackOverflow {
public static void main(String[] args) {
infiniteRun();
// ...
}
private static void infiniteRun() {
infiniteRun();
}
}
|
This compliant solution shows a try-catch block that can be used to capture java.lang.Error or java.lang.Throwable. A log entry can be made at this point, followed by attempts to free key system resources in the finally block.
public class StackOverflow {
public static void main(String[] args) {
try {
infiniteRun();
} catch(Throwable t) {
// Forward to handler
} finally {
// Free cache, release resources
}
// ...
}
private static void infiniteRun() {
infiniteRun();
}
}
|
Note that this solution catches Throwable in an attempt to handle the error; it is an exception to ERR08-J. Do not catch NullPointerException or any of its ancestors.
Allowing a system error to propagate out of a Java program may result in a denial-of-service attack.
| [JLS 2011] | §11.2, "Compile-Time Checking of Exceptions" |
| [Kalinovsky 2004] | Chapter 16, "Intercepting Control Flow: Intercepting System Errors" |
In the event of actually running out of memory, it is likely that some program data will be in an inconsistent state. Consequently, it might be best to restart the process. If an attempt is made to carry on, reducing the number of threads, or just cycling them, may be a good idea because threads often leak memory.
The methods
Thread.setUncaughtExceptionHandler()andThreadGroup.uncaughtException()can be used to help deal with anOutOfMemoryErrorin threads.