3.2 Understand the OutOfMemoryError Exception

翻译+理解:

One common indication of a memory leak is the java.lang.OutOfMemoryError exception. Usually, this error is thrown when there is insufficient space to allocate an object in the Java heap. In this case, The garbage collector cannot make space available to accommodate a new object, and the heap cannot be expanded further. Also, this error may be thrown when there is insufficient native memory to support the loading of a Java class. In a rare instance, a java.lang.OutOfMemoryError may be thrown when an excessive amount of time is being spent doing garbage collection and little memory is being freed.

内存泄漏的一个常见表现是抛出java.lang.OutOfMemoryError异常。通常,当Java堆中没有足够的空间分配给一个对象时会抛出这个错误。在这种情况下,垃圾回收器GC没有回收足够的空间来容纳一个新的对象,并且堆不能进一步拓展。另外,当没有足够的本地内存去加载一个Java类时也会抛出这个错误。在少数情况下,当有大量的时间被花在垃圾回收但只有少量内存被释放时,也可能出现OOM。

When a java.lang.OutOfMemoryError exception is thrown, a stack trace is also printed.

当OOM异常抛出时,会打印堆栈信息。

The java.lang.OutOfMemoryError exception can also be thrown by native library code when a native allocation cannot be satisfied (for example, if swap space is low).

当不能满足本地分配时(例如,如果交换空间太小)本地库代码会抛出OOM。

An early step to diagnose an OutOfMemoryError exception is to determine the cause of the exception. Was it thrown because the Java heap is full, or because the native heap is full? To help you find the cause, the text of the exception includes a detail message at the end, as shown in the following exceptions.

初步诊断OOM异常的方法是寻找引起异常的原因。是因为Java堆空间满了还是本地堆空间满了?为了帮助找到原因,下文列出的异常包含了详细的信息。

Exception in thread thread_name: java.lang.OutOfMemoryError: Java heap space

Cause: The detail message Java heap space indicates object could not be allocated in the Java heap. This error does not necessarily imply a memory leak. The problem can be as simple as a configuration issue, where the specified heap size (or the default size, if it is not specified) is insufficient for the application.

原因:Java堆栈的详细信息表明了对象不应该被分配在Java堆中。这个错误并不一定意味着内存泄漏。当特定的堆大小(如果没有指定就是默认的大小)对应用程序不够时,这个错误就和配置问题一样简单。

In other cases, and in particular for a long-lived application, the message might be an indication that the application is unintentionally holding references to objects, and this prevents the objects from being garbage collected. This is the Java language equivalent of a memory leak. Note: The APIs that are called by an application could also be unintentionally holding object references.

在其他情况下,尤其对一个长期存活的应用,信息可能显示应用程序在无意中一直引用对象从而阻止对象被垃圾回收。Java语言中,这和内存泄漏类似。注意:应用程序调用的APIs也可能无意一直引用对象。

One other potential source of this error arises with applications that make excessive use of finalizers. If a class has a finalize method, then objects of that type do not have their space reclaimed at garbage collection time. Instead, after garbage collection, the objects are queued for finalization, which occurs at a later time. In the Oracle Sun implementation, finalizers are executed by a daemon thread that services the finalization queue. If the finalizer thread cannot keep up, with the finalization queue, then the Java heap could fill up and this type of OutOfMemoryError exception would be thrown. One scenario that can cause this situation is when an application creates high-priority threads that cause the finalization queue to increase at a rate that is faster than the rate at which the finalizer thread is servicing that queue.

另一个可能的错误原因是应用程序使用了过多的finalizers。当一个类有一个finalize方法时,该类的对象没有时间来重申垃圾回收时间。并且在后段时间,当垃圾回收后,对象排队进行finalization。在Oracle Sun执行时,finalizers被后台的daemon守护线程执行,这些daemon线程服务于finalization队列。如果finalizer线程跟不上finalization队列的速度,然后Java堆会满,这种类型的OOM异常会被抛出。一个可能造成这种场景的情况是:应用程序创建了高优先级的线程,造成了finalization队列增加的速度比服务于队列的finalizer线程更快。

Action: You can find more information about how to monitor objects for which finalization is pending in Monitor the Objects Pending Finalization. See Finalization and Weak, Soft, and Phantom References in Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide for information about detecting and migrating from finalization.

方法:你可以在 Monitor the Objects Pending Finalization找到更多关于如何监控对象将finalization悬挂的信息。参考Java平台的 Finalization and Weak, Soft, and Phantom References ,关于探测和从finalizaton迁徙的标准版本HotSpot虚拟机垃圾回收的指导手册。

Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceeded

Cause: The detail message “GC overhead limit exceeded” indicates that the garbage collector is running all the time and Java program is making very slow progress. After a garbage collection, if the Java process is spending more than approximately 98% of its time doing garbage collection and if it is recovering less than 2% of the heap and has been doing so far the last 5 (compile time constant) consecutive garbage collections, then a java.lang.OutOfMemoryError is thrown. This exception is typically thrown because the amount of live data barely fits into the Java heap having little free space for new allocations.

原因:详细信息"GC overhead limit exceeded"表明垃圾回收器一直在运行,Java程序进展很慢。经过一个垃圾回收后,如果Java进程正在花超过大约98%的时间做垃圾回收,但是恢复着少于2%的堆空间,并且一直在做最后5个(编译时间是常量)连续的垃圾回收器,然后就抛出了OOM。这个异常通常是因为存活的数据很难容纳进只有一点点空间用于新分配的Java堆。

Action: Increase the heap size. The java.lang.OutOfMemoryError exception for GC Overhead limit exceeded can be turned off with the command line flag -XX:-UseGCOverheadLimit.

方法:增加堆大小。GC Overhead limit exceeded对应的OOM异常可以通过命令行命令-XX:-UseGCOverheadLimit来关闭。

Exception in thread thread_name: java.lang.OutOfMemoryError: Requested array size exceeds VM limit

Cause: The detail message “Requested array size exceeds VM limit” indicates that the application (or APIs used by that application) attempted to allocate an array that is larger than the heap size. For example, if an application attempts to allocate an array of 512 MB but the maximum heap size is 256 MB then OutOfMemoryError will be thrown with the reason Requested array size exceeds VM limit.

原因:详细信息"请求的数组大小超过了VM的限制"表明了应用程序(或应用程序使用的APIs)尝试去分配一个比堆空间更大的数组。例如:如果一个程序尝试去分配一个521MB大小的数组,但最大堆只有256MB,然后就发生了Requested array size exceeds VM limit的OOM异常。

Action: Usually the problem is either a configuration issue (heap size too small), or a bug that results in an application attempting to create a huge array (for example, when the number of elements in the array is computed using an algorithm that computes an incorrect size).

方法:通常问题是配置问题(堆太小),或者是一个bug导致应用程序尝试去创建一个大的数组(例如,使用了一个计算不正确大小的算法计算数组的元素)。

Exception in thread thread_name: java.lang.OutOfMemoryError: Metaspace

Cause: Java class metadata (the virtual machines internal presentation of Java class) is allocated in native memory (referred to here as metaspace). If metaspace for class metadata is exhausted, a java.lang.OutOfMemoryError exception with a detail MetaSpace is thrown. The amount of metaspace that can be used for class metadata is limited by the parameter MaxMetaSpaceSize, which is specified on the command line. When the amount of native memory needed for a class metadata exceeds MaxMetaSpaceSize, a java.lang.OutOfMemoryError exception with a detail MetaSpace is thrown.

原因:Java类的metadata(虚拟机内部的Java类表示)在本地内存中分配(在这里指metaspace元空间)。如果类元数据的元空间耗尽的话,一个带有详细MetaSpace的OOM异常被抛出。用于类元数据的元空间的大小通过参数MaxMetaSpaceSize限制,可以在命令行设置。当类元数据需要的本地内存的大小超过了MaxMetaSpaceSize时,有详细MetaSpace的OOM异常被抛出。

Action: If MaxMetaSpaceSize, has been set on the command-line, increase its value. MetaSpace is allocated from the same address spaces as the Java heap. Reducing the size of the Java heap will make more space available for MetaSpace. This is only a correct trade-off if there is an excess of free space in the Java heap. See the following action for Out of swap space detailed message.

方法:如果已经在命令行设置了MaxMetaSpaceSize,增加它的值。MetaSpace像Java堆一样在相同的地址空间分配。减少Java堆大小,则MetaSpace会有更多可用空间。如果Java堆有足够的空闲空间那这是唯一一个正确的trade-off方法。看下面"超出交换空间"详细信息的解决方法。

Exception in thread thread_name: java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?

Cause: The detail message “request size bytes for reason. Out of swap space?” appears to be an OutOfMemoryError exception. However, the Java HotSpot VM code reports this apparent exception when an allocation from the native heap failed and the native heap might be close to exhaustion. The message indicates the size (in bytes) of the request that failed and the reason for the memory request. Usually the reason is the name of the source module reporting the allocation failure, although sometimes it is the actual reason.

原因:详细信息“请求大小字节的原因,超出交换空间”似乎看起来是一个OOM异常。然而,当本地堆空间分配失败后,本地堆空间可能会耗尽关闭,Java的HotSpot虚拟机会报告这个明显的异常。这个信息表明请求的大小(以字节)失败以及内存请求的原因。通常原因是源代码模块报告了分配失败,尽管有时候这才是真正的原因。

Action: When this error message is thrown, the VM invokes the fatal error handling mechanism (that is, it generates a fatal error log file, which contains useful information about the thread, process, and system at the time of the crash). In the case of native heap exhaustion, the heap memory and memory map information in the log can be useful. For more information about understanding the fatal error log file, see Appendix A.

方法:当这个错误信息被抛出时,虚拟机调用了重大错误处理机制(它产生了一个重大错误日志文件,包含了计算机瘫痪死机时关于线程、进程和系统的有用信息)。在本地堆空间耗尽之时,堆内存和日志中的内存映射信息会很有用。更多关于重大错误日志文件的信息,请看附录A。

carsh:(计算机)瘫痪,死机

If this type of the OutOfMemoryError exception is thrown, you might need to use troubleshooting utilities on the operating system to diagnose the issue further. For more information about tools available for various operating systems, see Native Operating System Tools.

如果这种类型的OOM异常被抛出,你可能需要去使用操作系统上的问题排查工具进一步诊断问题。更多关于不同操作系统的的可用工具,请参考Native Operating System Tools

Exception in thread thread_name: java.lang.OutOfMemoryError: Compressed class space

Cause: On 64-bit platforms a pointer to class metadata can be represented by a 32-bit offset (with UseCompressedOops). This is controlled by the command line flag UseCompressedClassPointers (on by default). If the UseCompressedClassPointers is used, the amount of space available for class metadata is fixed at the amount CompressedClassSpaceSize. If the space needed for UseCompressedClassPointers exceeds CompressedClassSpaceSize, a java.lang.OutOfMemoryError with detail Compressed class space is thrown.

原因:在64位平台,一个类元数据的指针可以用32位的偏移量表示(和UseCompressedOops)。这个通过命令行的标记UseCompressedClassPointers控制(默认)。如果UseCompressedClassPointers被使用了,类元数据的可用空间大小被固定在CompressedClassSpaceSize。如果UseCompressedClassPointers需要的空间大小超过了CompressedClassSpaceSize,有详细压缩类空间的OOM异常抛出。

Action: Increase CompressedClassSpaceSize to turn off UseCompressedClassPointers. Note: There are bounds on the acceptable size of CompressedClassSpaceSize. For example -XX: CompressedClassSpaceSize=4g, exceeds acceptable bounds will result in a message such as CompressedClassSpaceSize of 4294967296 is invalid; must be between 1048576 and 3221225472.

方法:增加CompressedClassSpaceSize,关闭UseCompressedClassPointers。注意:这里对CompressedClassSpaceSize可接受大小有限制。例如-XX: CompressedClassSpaceSize=4g,超出了可接受的边界,将会导致CompressedClassSpaceSize of 4294967296 is invalid; must be between 1048576 and 3221225472这样的信息。

Note: There is more than one kind of class metadata - klass metadata and other metadata. Only klass metadata is stored in the space bounded by CompressedClassSpaceSize. The other metadata is stored in Metaspace.

注意:有超过一种的类元数据,- klass 元数据和其他的元数据。只有- klass 元数据被存储在由CompressedClassSpaceSize限制的空间中。其他元数据存储在元空间中。

Exception in thread thread_name: java.lang.OutOfMemoryError: reason stack_trace_with_native_method

Cause: If the detail part of the error message is “reason stack_trace_with_native_method” and a stack trace is printed in which the top frame is a native method, then this is an indication that a native method has encountered an allocation failure. The difference between this and the previous message is that the allocation failure was detected in a Java Native Interface (JNI) or native method rather than in the JVM code.

原因:如果一部分错误信息是"reason stack_trace_with_native_method",堆栈信息被打印在是本地方法的栈帧位置,这就暗示着本地方法分配失败。这个和前面信息的区别是:分配失败在JNI Java本地接口或本地方法被检测到而不是JVM代码中。

Action: If this type of the OutOfMemoryError exception is thrown, you might need to use native utilities of the OS to further diagnose the issue. For more information about tools available for various operating systems, see Native Operating System Tools.

方法:如果这种类型的OOM异常被抛出,你可能需要去使用操作系统上的本地工具进一步诊断问题。更多关于不同操作系统的的可用工具,请参考Native Operating System Tools