java.lang.OutOfMemoryError (OOM)解密 & Java heap dumps 解析 (一)

Unveiling the java.lang.Out OfMemoryError
And dissecting Java heap dumps


When we encounter a java.lang.OutOfMemoryError, we often find that Java heap dumps, along with other artifacts, are generated by the Java Virtual Machine. If you feel like jumping right into a Java heap dump when you get a java.lang.OutOfMemoryError, don't worry, it's a normal thought. You may be able to discover something serendipitously, but it's not always the best idea to analyze Java heap dumps, depending on the situation you are facing. We first need to investigate the root cause of the java.lang.OutOfMemoryError.

         当我们遇到java.lang.OutOfMemoryError ,我们常常会发现JVM会进行Java堆转储,以及由Java虚拟机生成的其他文件。当你得到一个java.lang.OutOfMemoryError时,如果你感觉刚好JVM在进行Java堆转储 ,不要担心,这是正常的想法。你也许可以侥幸发现一些信息,但这并不总是分析Java堆转储的最好方式,因为这取决于你所面对的实际场景。我们首先需要调查java.lang.OutOfMemoryError的根本原因。

Only after the root cause is identified can we decide whether or not to analyze Java heap dumps. What is a java.lang.OutOfMemoryError? Why in the world does it occur? Let's find out.

      只有我们确定OOM的根本原因后,我们才能决定是否要进行Java堆转储分析。那么什么是 java.lang.OutOfMemoryError?什么情况下会发生 java.lang.OutOfMemoryError?下面我们来探究下。

What Is a java.lang.OutOfMemoryError?
A java.lang.OutOfMemoryError is a subclass of java.lang.VirtualMachineError that is thrown when the Java Virtual Machine is broken or has run out of resources that are necessary to continue the operation of the Java Virtual Machine. Obviously, memory is the exhausted resource for a java.lang.OutOfMemoryError, which is thrown when the Java Virtual Machine cannot allocate an object due to memory constraints. Unfortunately, the Java specification of java.lang.OutOfMemoryError does not elaborate further on what kind of memory it's talking about.

        java.lang.OutOfMemoryError 是java.lang.VirtualMachineError的一个子类,当JVM崩溃或者当使得JVM继续运行的必备资源耗尽时会抛出java.lang.OutOfMemoryError异常。很明显,对于java.lang.OutOfMemoryError来说,内存则是被耗尽的资源,由于内存耗尽限制,JVM无法为一个对象分配内存。

        不幸的是,Java规范并没有进一步说明java.lang.OutOfMemoryError涉及的是哪种内存。

There are six different types of runtime data areas, or memory areas, in the Java Virtual Machine (seeFigure 1).

在JVM里面有6种不同类型的运行时数据区或内存区,如下:

  1. Program Counter Register (程序计数器寄存器
  2. Java Virtual Machine Stack Java虚拟机堆栈)
  3. Heap (堆)
  4. Method Area (方法区)
  5. Runtime Constant Pool (运行时常连池)
  6. Native Method Stack (本地方法栈)

The Program Counter Register, also known as the pc register, stores the address of the Java byte code instruction that is currently being executed (just like the processor register in your central processing unit of the device from which you are reading or printing this article). You will not see a java.lang.OutOfMemoryError from the pc register since a program counter is not conventionally considered as a memory.

       程序计数器寄存器,也被称为PC寄存器,存储当前正在执行(就像在从中你正在阅读或打印这篇文章您设备的中央处理单元的处理器寄存器)的Java字节码指令的地址你不会看到一个由于PC寄存器错误产生java.lang.OutOfMemoryError,因为程序计数器通常不被视为内存。

Java Virtual Machine Stacks contain frames where data, return values, and partial execution results are stored. Java Virtual Machine Stacks can be expanded during runtime. If there's not enough memory for the expansion of an existing Java Virtual Machine stack, or for the creation of a new Java Virtual Machine stack for a new thread, the Java Virtual Machine will throw a java.lang.OutOfMemoryError.

        Java虚拟机堆栈包含一系列的帧,也就是数据、返回值和部分执行结果存储的地方。Java虚拟机堆栈可以在运行时扩展。如果没有足够的内存用于现有的Java虚拟机堆的扩大,或为一个新的线程创建一个Java虚拟机栈,此时, Java虚拟机将会抛出一个java.lang.OutOfMemoryError 。

The Heap is where instances of Java classes and arrays are allocated. A java.lang.OutOfMemoryError will be thrown when there is not enough memory available for instances of Java classes or arrays.

        堆是为Java类和数组的实例分配内存的地方。当没有足够的可用于Java类或数组的实例的内存分配时,将会抛出java.lang.OutOfMemoryError。

The Method Area stores class-related information, the runtime constant pool, for instances, the code for methods and constructors, and field/method data. If there's not enough memory in the method area, you will encounter java.lang.OutOfMemoryError.

        方法区存储类相关的信息、运行时的常量池;例如,对于类实例来说,就是方法和构造方法以及字段或方法数据的代码。如果方法区内没有足够的内存,你同样会碰到java.lang.OutOfMemoryError 异常。

The Runtime Constant Pool contains constants such as field references and literals. A java.lang.OutOfMemoryError will be thrown when not enough memory is available for the construction of the runtime constant pool area.

        运行时常量池包含像字段引用以及文本这样的常量。当没有足够的内存可用于运行时常量池区的构建时,也会抛出java.lang.OutOfMemoryError。

Native Memory Stacks store conventional stacks, also known as C stacks, to support native methods that are written in a non-Java language such as C/C++. Native memory stacks can be expanded during runtime. If there's not enough memory for the expansion of an existing native memory stack or for the creation of a new native memory stack for a new thread, you would see a java.lang.OutOfMemoryError.

        本地内存栈,存储诸如C语言栈这种传统的栈,用于支持像C / C + +这种非Java语言编写的本地方法。本地内存栈同样也可以在运行时扩展。如果没有足够的内存类扩展现有的本地内存栈或为一个新的线程创建本地内存栈,你将会看到一个java.lang.OutOfMemoryError 。

You may have seen a java.lang.StackOverflowError, which is completely different from a java.lang.OutOfMemoryError. A java.lang.StackOverflowError is thrown when native memory stacks or Java Virtual Machine stacks need more memory than is configured. In most IBM Java Virtual Machine implementations, the -Xmso command-line option controls the stack size for operation system threads or native thread, and the -Xss command-line option controls the stack size for Java threads. In some implementations, such as Sun Microsystems HotSpot Java Virtual Machine, the Java methods share stack frames with C/C++ native code. The maximum stack size for a thread can be configured with the -Xss Java command-line option. The default sizes of these options vary by platform and implementation, but are usually between 256 Kbytes-1024 Kbytes. Please refer to the documentation of your Java virtual machine for more specific information. We will cover more about java.lang.StackOverflowError in a separate article.

        你也许看到过java.lang.StackOverflowError ,它是与java.lang.OutOfMemoryError完全不同的一种错误。当本地内存栈或Java虚拟机栈需要比配置更多的内存时,就会抛出一个java.lang.StackOverflowError。在大多数IBM的Java虚拟机的实现中, - Xmso设置的命令行选项控制运行系统线程或本地线程的堆栈大小,而-Xss命令行选项则控制对Java线程的栈大小。在一些实现中,如Sun公司的HotSpot Java虚拟机,Java方法与C / C + +的本机代码共享栈帧。线程的最大堆栈大小可以使用-Xss Java命令行选项配置。这些选项的默认大小因平台和JVM实现而异,但通常是256KB~1024KB之间。请参阅您的Java虚拟机的来查看更多的具体信息。我们将会在另一篇文章中详细介绍更多关于java.lang.StackOverflowError的内容。

Now that we understand which memory areas could cause a java.lang.OutOfMemoryError, let's take a look at actual error messages. What does a java.lang.OutOfMemoryError look like and how can I address each symptom? Have you ever seen a java.lang.OutOfMemoryError similar to the following?

        现在我们已经了解了哪些内存区可能会引起 java.lang.OutOfMemoryError,下面我们来看看一些实际的错误消息。 java.lang.OutOfMemoryError到底是什么样的?我们如何去针对不同的错误症状来去解决OOM问题。大家有没有见过像类似下面这一行所展示的 java.lang.OutOfMemoryError?

java.lang.OutOfMemoryError: Requested array size exceeds VM limit

This error message indicates that there is a memory request for an array but that's too large for a predefined limit of a virtual machine. What do we do if we encounter this kind of java.lang.OutOfMemoryError? We need to check the source code to make sure that there's no huge array created dynamically or statically. Fortunately, latest virtual machines usually do not have this limit.

        通过这个错误消息我们可以了解到,是由于我们要为一个数组分配内存,但是这个请求的数组内存大小已经超过了JVM的预定义大小限制。那如果我们碰到这种场景的 java.lang.OutOfMemoryError该怎么办呢?如果遇到这种情况,我们就需要检查下源代码以确定程序没有动态或者静态的创建这样的超大数组,幸运的是,在最新版的虚拟机中则没有这个限制。

java.lang.OutOfMemoryError: PermGen space

You will see an OutOfMemoryError when the Permanent Generation area of the Java heap is full, like the above message.

        在Java堆的永久代区域内存被填满时,你同样也会看到像上面那样的OOM错误信息。

On some Java Virtual Machines, such as Sun Microsystems' HotSpot Java Virtual Machine, a dedicated memory area called permanent generation (or permanent region) stores objects that describe classes and methods. We can visualize the usage of a permanent generation with the IBM Pattern Modeling and Analysis Tool for the Java Garbage Collector.

        在一些Java虚拟机中,例如,像Sun Microsystems(已被Oracle收购)的HotSpot虚拟机,会有一个称之为持久代(或持久区)的专用内存区域,用来存储描述类和方法的对象,我们可以使用IBM的PMAT工具通过可视化的方式来查看持久代的情况。

In Figure 2 we enabled the "Max Perm" button and  the "Used Tenured" button to visualize permanent generation usage and its maximum size. We can see that the used amount of permanent generation reaches its maximum limit. That's why we're getting the java.lang.OutOfMemoryError: PermGen space message. If there's no memory leak, we can just use the -XX:MaxPermSize command-line option to increase the maximum limit of the permanent generation. For example,

-XX:MaxPermSize=128m

will set the maximum size of the permanent generation to 128 Mbytes.

        在图2中,我们通过点击"Max Perm"和 "Used Tenured"按钮来可视化展示持久代的使用情况和持久代的最大大小。我们通过图看到持久代的使用数量已经达到持久代的最大限制大小,这也就是为什么我们会得到一个“java.lang.OutOfMemoryError: PermGen space ”异常消息的原因。如果不存在内存泄露的话,我们可以使用通过调节 -XX:MaxPermSize 命令行选项来增加持久代的最大大小。例如,我们可以设置 -XX:MaxPermSize=128m 来将持久代大小设置为128MB。

So far we've seen a Java.lang.OutOfMemoryError due to exhaustion in the Java heap or an area in the Java heap such as permanent generation. Surprisingly, a Java.lang.OutOfMemoryError can be thrown when the Java Virtual Machine cannot find any more memory in the native memory as well as in the Java heap. How can we tell whether it's caused by the Java heap or native memory?

        到目前为止,我们已经看到Java堆内存耗尽或者Java堆的持久代内存耗尽而产生java.lang.OutOfMemoryError的情况。但是奇怪的是,当Java虚拟机在本地内存里面无法分配更多的内存时,同样会抛出java.lang.OutOfMemoryError错误,如同Java堆空间不足,同样产生的java.lang.OutOfMemoryError错误一样。那我们如何区分这个OOM是由于Java堆存储空间耗尽产生的?还是本地内存空间不够产生的呢?


In the following message, there's no information in the message whetherjava.lang.OutOfMemoryError is caused by the Java heap or native memory:

    在下面这个错误信息中,没有足够的信息可以判断出这个OOM是由于Java堆产生的还是本地内存产生的:

JVMDUMP013I Processed dump event "systhrow",detail "java/lang/OutOfMemoryError".


In the following case, the Java virtual machine is kind enough to tell usthat there's native memory exhaustion. In the message, the Java virtual machinesays "allocateMemory failed" which means a native memory allocationfailed:

    在下面这种情况,Java虚拟机提供了足够的信息,我们可以藉由此判断出OOM是由于本地内存耗尽所导致的本地内存分配失败。

java.lang.OutOfMemoryError: JVMCI046: allocateMemoryfailed


In the following message, there's no clue as to whether it's native memoryor a Java heap. Fortunately we have a line number, 20, and the source code filename, HeapExhaustionSimulator.java. This might be Java heap related.

    在下面这则简短错误消息中,我们也没有找到任何线索来说明OOM是由于本地内存或者Java堆内存所致。幸运的是,我们可以通过HeapExhaustionSimulator.java的第20行源代码来查找,也许就跟Java堆有关。

JVMDG274: Dump Handler has Processed OutOfMemory.
Exception in thread "main" java.lang.OutOfMemoryError
at HeapExhaustionSimulator.main(HeapExhaustionSimulator.java:20)


In the following message, there's no clue whether it's native memory or aJava heap. But "sun.misc.Unsafe.allocateMemory(Native Method)"indicates that it might be native memory related.

    在下面这则简短错误消息中,我们同样也没有找到任何线索来说明OOM是由于本地内存或者Java堆内存所致。但是,"sun.misc.Unsafe.allocateMemory(Native Method)" 这句也许说明了可能跟本地内存不足有关。

Exception in thread "main"java.lang.OutOfMemoryError
at sun.misc.Unsafe.allocateMemory(Native Method)
at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:99)
at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:288)
at NativeMemorySimulator.main(NativeMemorySimulator.java:11)


In the following message, the  Java Virtual Machine indicates thatthe Java heap space is related to the java.lang.OutOfMemoryError.

    同样,下面的错误消息说明OOM跟Java堆空间有关。

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid6280.hprof ...
Heap dump file created [50549348 bytes in 1.444 secs]


You may have seen a java.lang.OutOfMemoryError similar to the following:

    你可能也见过像下面这样的OOM内容:

java.lang.OutOfMemoryError: requested NNN bytes for MMMM.Out of swap space?

Literally you could check the operating system configuration for swapspace. It seems that the Java Virtual Machine is not sure if the swap space isthe root cause of the problem (?).We can check whether this Java VirtualMachine is consuming too much native memory .We also need to make sure there'senough memory for this JVM and no other processes are consuming most of memoryresource. The last thing we can try is to find any known defects related to themodule, MMMM.

    根据上面错误消息的字面理解,你可以检查下操作系统的Swap空间配置(仅Linux/Unix OS才有)。这条消息看起来似乎是Java虚拟机并不确定Swap空间是产生OOM的根本原因。我们可以进一步检查下java虚拟机是否使用了太多的本地内存。我们同样也需要确认下我们是否为Java虚拟机预留了足够的内存,而且没有其他进程使用了大部分内存资源。最后,我们可以尝试查找任何与MMMM模块有关的问题。


java.lang.OutOfMemoryError: unable to create new nativethread

This kind of message is seen when you have an excessive number of threadsor if the native memory is exhausted and a thread is attempting to be created.

    另外,当虚拟机已经有过多的线程或者在本地内存耗尽时再尝试创建一个线程时,会抛出上面这种OOM错误。

 下一篇:java.lang.OutOfMemoryError (OOM)解密 & Java heap dumps 解析 (二)

原文链接地址:http://java.sys-con.com/node/1229281



  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值