简体   繁体   English

OutOfMemory错误,但应用程序在Java中继续

[英]OutOfMemory error but application continues in java

I have faced OutOfMemory error in my application. 我在应用程序中遇到了OutOfMemory错误。 But the thing is my application keeps on running though it has thrown OutOfMemeory. 但问题是,尽管我的应用程序抛出了OutOfMemeory,但仍保持运行状态。 After some two minutes later, JVM has quit and pid file got genearted throwing 两分钟后,JVM已退出,并且pid文件被普遍抛出

java.lang.OutOfMemoryError: requested 746 bytes for jbyte in 
    /BUILD_AREA/jdk6_21/hotspot/src/share/vm/prims/jni.cpp. Out of swap space?.

1) Is it possible for JVM to continue running even after throwing OutOfMemory error ? 1)即使抛出OutOfMemory错误,JVM是否仍可以继续运行? 2)Also can you give me some direction to investigate on this further? 2)您还可以给我一些指导,以便对此进行进一步调查吗?

I am pasting the excerpt from log to get a better understanding. 我粘贴了日志摘录,以更好地理解。

1) There are two out of memory errors. 1)有两个内存不足错误。 One at 2011.12.09 16.04.09:446 and another at 2011.12.09 16.04.40:818 一个在2011.12.09 16.04.09:446,另一个在2011.12.09 16.04.40:818

    2011.12.09 16.04.09:446 664849490 WARNING {HTTP@9800-168}RULEZ runtime exception [transcoding]
    java.lang.OutOfMemoryError
            at java.util.zip.Inflater.inflateBytes(Native Method)
            at java.util.zip.Inflater.inflate(Inflater.java:238)
            at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:135)
            at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:105)
            at java.util.jar.JarVerifier$VerifierStream.read(JarVerifier.java:428)
            at java.io.FilterInputStream.read(FilterInputStream.java:66)
            at com.sun.mail.util.LineInputStream.readLine(LineInputStream.java:75)
            at javax.mail.Session.loadProvidersFromStream(Session.java:932)
            at javax.mail.Session.access$000(Session.java:174)
            at javax.mail.Session$1.load(Session.java:870)
            at javax.mail.Session.loadResource(Session.java:1084)
            at javax.mail.Session.loadProviders(Session.java:889)
            at javax.mail.Session.<init>(Session.java:210)
            at javax.mail.Session.getInstance(Session.java:249)
    .
    .
    .[Application continues here]
    .
    .
    .
    2011.12.09 16.04.40:818 664882092 WARNING {HTTP@9800-168}RULEZ runtime exception [transcoding]
    java.lang.OutOfMemoryError
            at java.util.zip.Inflater.inflateBytes(Native Method)
            at java.util.zip.Inflater.inflate(Inflater.java:238)
            at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:135)
            at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:105)
            at java.util.jar.JarVerifier$VerifierStream.read(JarVerifier.java:428)
            at java.io.FilterInputStream.read(FilterInputStream.java:66)
            at com.sun.mail.util.LineInputStream.readLine(LineInputStream.java:75)
            at javax.mail.Session.loadProvidersFromStream(Session.java:932)
            at javax.mail.Session.access$000(Session.java:174)
            at javax.mail.Session$1.load(Session.java:870)
            at javax.mail.Session.loadResource(Session.java:1084)
            at javax.mail.Session.loadProviders(Session.java:889)
            at javax.mail.Session.<init>(Session.java:210)
            at javax.mail.Session.getInstance(Session.java:249)
    .
    .
    .
    .
    .

2) At Dec 9 16:07,JVM quits and created pid file as below. 2)在12月9日16:07,JVM退出并创建pid文件,如下所示。 So, there is ~2 minutes gap between OutOFMemory error log statement and for jvm to quit and create pid file. 因此,OutOFMemory错误日志语句与jvm退出并创建pid文件之间大约有2分钟的间隔。

    $ls

    -rw-rw-r--   1 ins ins     156076 Dec  9 16:07 hs_err_pid29157.log
    -rw-------   1 ins ins 3055525888 Dec  9 16:07 core.29157


    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    # java.lang.OutOfMemoryError: requested 746 bytes for jbyte in /BUILD_AREA/jdk6_21/hotspot/src/share/vm/prims/jni.cpp. Out of swap space?
    #
    #  Internal Error (allocation.inline.hpp:39), pid=21129, tid=667401120
    #  Error: jbyte in /BUILD_AREA/jdk6_21/hotspot/src/share/vm/prims/jni.cpp
    #
    # JRE version: 6.0_21-b06
    # Java VM: Java HotSpot(TM) Server VM (17.0-b16 mixed mode linux-x86 )
    # If you would like to submit a bug report, please visit:
    #   http://java.sun.com/webapps/bugreport/crash.jsp
    #

    ---------------  T H R E A D  ---------------

    Current thread (0x2f929000):  JavaThread "DRIVER:adapter:12:7" [_thread_in_vm, id=21834, stack(0x27c5b000,0x27c7c000)]

    Stack: [0x27c5b000,0x27c7c000],  sp=0x27c7a874,  free space=7e27c7c000k
    Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
    V  [libjvm.so+0x6a9262]
    V  [libjvm.so+0x2b277f]
    V  [libjvm.so+0x3c0b0f]
    C  [libocijdbc10.so+0x108ff]
    C  [libocijdbc10.so+0x11788]  Java_oracle_jdbc_driver_T2CConnection_lobGetLength+0x30
    J  oracle.jdbc.driver.T2CConnection.lobGetLength(J[BI)J

    Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
    J  oracle.jdbc.driver.T2CConnection.lobGetLength(J[BI)J
    J  oracle.jdbc.driver.T2CConnection.length(Loracle/sql/BLOB;)J
    J  com.fh.common.database.ReadConnectionImpl.getByteArray(Ljava/lang/String;Ljava/sql/ResultSet;I)[B
    J  com.fh.common.database.ReadConnectionWrapper.getByteArray(Ljava/lang/String;Ljava/sql/ResultSet;I)[B
    J  com.fh.mr.storage.MultiJDBCStorage.fillInitiator(Lcom/fh/common/database/ReadConnection;Ljava/lang/String;Ljava/sql/ResultSet;Lcom/fh/mr/router/TransactionResponder;)Lcom/fh/mr/router/TransactionInitiator;
    J  com.fh.mr.storage.MultiJDBCStorage.addInitiators(Lcom/fh/mr/router/TransactionResponder;Ljava/util/Collection;)V
    J  com.fh.mr.storage.CacheStorage.getResponderByTransactionID(Ljava/lang/String;)Lcom/fh/mr/router/TransactionResponder;
    j  com.fh.mr.router.RoutingEngine.getResponderByTransactionID(Ljava/lang/String;)Lcom/fh/mr/router/TransactionResponder;+5
    j  com.fh.mr.router.RoutingEngine.scheduleStatusResend(Ljava/lang/String;)Z+53
    j  com.fh.mr.router.RoutingEngine.scheduleResend(Lcom/fh/mr/message/Message;I)Z+68
    j  com.fh.mr.drivers.Driver.getMessage(Ljava/lang/Object;)Lcom/fh/mr/message/Message;+260
    J  com.fh.mr.drivers.Driver$QueueWorker.run()V
    j  com.fh.common.threadpool.ThreadControl.run()V+47
    j  com.fh.common.threadpool.ThreadPool$PoolThread.run()V+467
    v  ~StubRoutines::call_stub

Thanks,
Vijay

Is it possible for JVM to continue running even after throwing OutOfMemory error ? 即使抛出OutOfMemory错误,JVM是否仍可以继续运行?

Sure. 当然。 The OutOfMemory error can be caught, and even if not, it just kills the current thread. 可以捕获OutOfMemory错误,即使没有,也只会杀死当前线程。 Any other threads can continue to run. 任何其他线程都可以继续运行。

Also can you give me some direction to investigate on this further? 您还可以给我一些指导,以便对此进行进一步调查吗?

According to the stacktrace, your program ran out of memory while trying to open some jar file. 根据stacktrace,您的程序试图打开一些jar文件时内存不足。 However, that does not necessary need to be the culprit (ie the task that ate up too much memory). 但是,这不一定是罪魁祸首(即占用过多内存的任务)。 You need to find out what part of your program uses too much memory, and then either reduce that somehow, or allocate more memory to the JVM. 您需要找出程序的哪个部分使用了过多的内存,然后以某种方式减少内存使用量,或为JVM分配更多的内存。

You should also watch for memory leaks which sometimes happen for long-running processes, especially when some classes get reloaded, for example. 您还应该注意长时间运行的进程有时会发生的内存泄漏,例如,某些类重新加载时。 If you find that you have a server process that slowly grows in size over time, a quick fix (easier than changing code) could be to restart it once in a while. 如果发现服务器进程的大小随着时间的推移缓慢增长,则快速解决方案(比更改代码更容易)可能是不时地重新启动它。

At Dec 9 16:07,JVM quits and created pid file as below. 在12月9日16:07,JVM退出并创建pid文件,如下所示。

The JVM crashed there with an internal error. JVM因内部错误而崩溃。 That should not happen. 那不应该发生。 However, this may very well have been caused by operating for two minutes very close to the memory limit. 但是,这很可能是由于在非常接近内存限制的情况下运行了两分钟而引起的。 After an OutOfMemory error, things tend to break. 在发生OutOfMemory错误后,事情往往会中断。 Do you get this crash report more often? 您会更频繁地获得该崩溃报告吗?

1) Is it possible for JVM to continue running even after throwing OutOfMemory error ? 1)即使抛出OutOfMemory错误,JVM是否仍可以继续运行?

Yes, after a fashion, depending on what the application is and what it is doing. 是的,遵循某种方式,取决于应用程序是什么以及正在做什么。

The lifecycle of an OOME is a follows: OOME的生命周期如下:

  • The application attempts to allocate some memory (a new object or array, a new thread stack, a non-heap buffer, etcera), and finds that it can't. 应用程序尝试分配一些内存(一个新的对象或数组,一个新的线程堆栈,一个非堆缓冲区等),并发现它不能。
  • (For a normal heap allocation) the GC runs ... and fails to reclaim enough memory. (对于正常的堆分配)GC运行...并且无法回收足够的内存。
  • An exception is thrown on the thread that attempted to allocate the memory. 尝试分配内存的线程上引发异常。

What happens next depends on how the application deals with the exception. 接下来发生的情况取决于应用程序如何处理异常。

  • If the application catches it and bails out, that is it. 如果应用程序将其捕获并解决,那就是。 The same if the OOME was thrown on the "main" thread and the application doesn't catch it. 如果将OOME抛出到“主”线程上,而应用程序没有捕获它,也是如此。
  • If the application catches it and attempts to resume then ... see below. 如果应用程序将其捕获并尝试恢复,则...参见下文。
  • If the application doesn't catch it, and the thread is NOT the main thread, then the thread dies but the application keeps going. 如果应用程序未捕获到该线程,并且该线程不是主线程,则该线程死亡,但应用程序继续运行。

So lets assume that we are "keeping going". 因此,假设我们正在“继续前进”。 Will it work? 能行吗 The answer is that it depends. 答案是,这取决于。

  • Can the application detect that the thread has died and recreate a replacement? 应用程序可以检测到线程已死亡并重新创建替换线程吗?
  • What was the application in the middle of doing when the OOME was thrown? 抛出OOME时正在执行的应用程序是什么?
  • Was it in the middle of updating a key data structure? 是在更新关键数据结构的过程中吗?
  • Has unwinding the stack caused enough objects to become eligible for garbage collection to allow the application to make progress? 展开堆栈是否已使足够的对象有资格进行垃圾回收以使应用程序取得进展?
  • Will the application just repeat the computation that it did before that resulted in the OOME? 应用程序会重复生成OOME之前的计算吗?

Unfortunately, the application typically can't continue due to the above issues. 不幸的是,由于上述问题,该应用程序通常无法继续运行。 And even when it can continue, it often will fail again fairly shortly. 即使它可以继续,它通常也会很快再次失效。 The root cause of the OOME in a long running application is typically a memory leak, and the best short-term cure is to restart the JVM and the application. 在长时间运行的应用程序中,OOME的根本原因通常是内存泄漏,最好的短期解决方法是重新启动JVM和应用程序。

2)Also can you give me some direction to investigate on this further? 2)您还可以给我一些指导,以便对此进行进一步调查吗?

If you have a memory leak, you probably can't deduce anything by looking at what was happening when the OOME was thrown. 如果存在内存泄漏,则可能无法通过查看抛出OOME时发生的情况来推断出任何东西。 The allocation that failed is unlikely to be the real cause of the problem. 分配失败很可能不是问题的真正原因。

So my advice would be to start by checking the application for memory leaks. 因此,我的建议是检查应用程序内存泄漏开始。

As others said OutOfMemoryError is an Error that can be caught and handled. 正如其他人所说, OutOfMemoryError是可以捕获和处理的错误。

To investigate the error further you will need to use VisualVM either to 要进一步调查错误,您将需要使用VisualVM来执行以下操作:

  • look at memory consumption on a live application 查看实时应用程序上的内存消耗
  • browse heap dump generated by java. 浏览Java生成的堆转储。

To generate the heap dump start your application with -XX:+HeapDumpOnOutOfMemoryError parameter, wait for the OutOfMemoryError, grab the heap dump and feed it to VisualVM. 要生成堆转储,请使用-XX:+HeapDumpOnOutOfMemoryError参数启动应用程序,等待OutOfMemoryError,获取堆转储并将其提供给VisualVM。

Googling for VisualVM and OutOfMemoryError will give you all kind of usage scenarios. 谷歌搜索VisualVM和OutOfMemoryError将为您提供各种使用方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM