2010-05-07 33 views
11
  • 沒有Java 6中,除了堆轉儲(java_pid14941.hprof)如何在生成線程轉儲Java的內存不足的錯誤

  • 這是發生了什麼事我的應用程序之一生成線程轉儲。

    java.lang.OutOfMemoryError:GC開銷超過限制 傾銷堆java_pid14941.hprof ...

  • 我確實發現ava_pid14941.hprof在工作目錄,但沒有發現其中含有線程轉儲的任何文件。當我得到這個OutOfMemory錯誤時,我需要知道所有線程在做什麼。

  • 是否有任何配置選項會在內存不足異常時除堆轉儲外還會生成線程轉儲?

回答

14

How to generate thread dump java on out of memory error?

你的問題可以簡化爲:

  • 如何生成線程轉儲

和:

  • 如何捕獲內存不足的錯誤(唐在這裏不注意反對者,他們錯過了更大的圖片,看我的評論)

所以它其實很簡單,你可以做這樣的:

  • 一旦捕獲未捕獲的異常安裝默認未捕獲的異常處理程序

  • ,檢查是否有一個OutOfMemoryError

  • 如果你有一個OutOfMemoryError,產生一個完整的線程轉儲,並要求用戶通過電子郵件發送給你或提供自動發送它

獎勵:它在1上正常工作。5太:)

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
    public void uncaughtException(final Thread t, final Throwable e) { 
     ... 
    } 

你可能想看看這個:

e.getMessage(); 

這:

Thread.getAllStackTraces(); 

我做這一切的時候在附帶的應用程序數百個不同的1.5和1.6 JVM(在不同的操作系統上)。

+5

請注意,無知的評論者/反對者可能會想出像*「你永遠不會捕捉OOM」這樣的無意義,但他們可能從來沒有在數百個系統上部署的Real-World TM Java應用程序上工作過。我一直這樣做**和**它只是起作用**。這使我能夠遠程調試和修復很多非常微妙的內存泄漏,這在測試過程中從未出現過。在這裏捕捉一個OOM是非常有意義的**,因爲整個觀點是要理解爲什麼OOM正在發生**。但不要驚訝,看到很多反對者在這裏不理解這個非常基本的事實**。 – SyntaxT3rr0r 2010-05-07 12:18:01

+0

基於這個答案,我創建了實用工具類UncaughtExceptionLogger(http://pastebin.com/e30g9y66)。這個你可以定義爲Spring bean,並且你都設置了擴展日誌記錄。 – snowindy 2014-12-17 04:37:36

0

我不認爲在java中有什麼東西可以爲您提供退出線程轉儲。我在必要時通過定期執行kill -3 pid的cronjob來解決此問題。是的,它確實使日誌雜亂一點,但佔用空間仍然可以忽略不計。

如果您患有OOM,那麼看看情況是如何演變爲線程式的可能是有益的。

+0

爲什麼downvote? – mindas 2010-05-08 10:32:29

20

如果您在Linux/Unix環境是,你可以這樣做:

-XX:OnOutOfMemoryError="kill -3 pid" 

這樣你就不必讓應用程序產生週期性的線程轉儲,你會得到一個快照,當它實際上是窒息。

+5

事實上,事實證明,您可以將在OOME上生成的Heap Dump加載到VisualVM中,然後單擊「堆轉儲中的線程」部分標題下的「顯示線程」鏈接。 – 2010-05-25 17:48:48

+7

'-XX:OnOutOfMemoryError =「kill -3%p」' - 你不需要手動解析和指定pid(https://forums.oracle.com/forums/thread.jspa?threadID=2374398&tstart= 60) – yetanothercoder 2013-02-27 13:49:30

2

當使用jstack觸發OnOutOfMemoryError時,可能觸發線程轉儲。例如: -

jstack -F pid > /var/tmp/<identifier>.dump 
0

基於接受的答案,我創建了工具類。這個你可以定義爲一個Spring bean,並且你都設置了擴展日誌記錄。

import java.util.Iterator; 
import java.util.Map; 

import javax.annotation.PostConstruct; 

import org.apache.commons.lang3.exception.ExceptionUtils; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

public class UncaughtExceptionLogger { 

    private final static Logger logger = LoggerFactory.getLogger(UncaughtExceptionLogger.class); 

    @PostConstruct 
    private void init() { 
     Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { 
      public void uncaughtException(final Thread t, final Throwable e) { 
       String msg = ExceptionUtils.getRootCauseMessage(e); 
       logger.error(String.format("Uncaght exception handler captured expcetion '%s'", msg), e); 
       if (msg.contains("unable to create new native thread")) { 
        String dump = captureThreadDump(); 
        logger.error(String.format(
          "OutOfMemoryError has been captured for threads limit. Thread dump: \n %s", dump), e); 
       } 
       if (ExceptionUtils.getRootCause(e) instanceof OutOfMemoryError) { 
        String dump = captureThreadDump(); 
        logger.error(String.format("OutOfMemoryError has been captured. Thread dump: \n %s", dump), e); 
       } 
      } 
     }); 
    } 

    public static String captureThreadDump() { 
     /** 
     * http://stackoverflow.com/questions/2787976/how-to-generate-thread- 
     * dump-java-on-out-of-memory-error 
     * http://henryranch.net/software/capturing-a-thread-dump-in-java/ 
     */ 
     Map<Thread, StackTraceElement[]> allThreads = Thread.getAllStackTraces(); 
     Iterator<Thread> iterator = allThreads.keySet().iterator(); 
     StringBuffer stringBuffer = new StringBuffer(); 
     while (iterator.hasNext()) { 
      Thread key = (Thread) iterator.next(); 
      StackTraceElement[] trace = (StackTraceElement[]) allThreads.get(key); 
      stringBuffer.append(key + "\r\n"); 
      for (int i = 0; i < trace.length; i++) { 
       stringBuffer.append(" " + trace[i] + "\r\n"); 
      } 
      stringBuffer.append(""); 
     } 
     return stringBuffer.toString(); 
    } 
}