Java內存溢出如何處理

背景介紹

新建Java對象時會在JVM的Heap中分配內存,對象不可達時其內存會被JVM GC回收,
可是當Heap中沒有多餘內存可供分配時,就會報OutOfMemory錯誤(如下簡稱OOM):java

嚴重: Unexpected death of background thread ContainerBackgroundProcessor[StandardEngine[Catalina]]
java.lang.OutOfMemoryError: Java heap space
	at org.apache.catalina.startup.HostConfig.checkResources(HostConfig.java:1379)

解決方法

解決方式很簡單——加大Heap:數據庫

set JAVA_OPTS=-Dfile.encoding=UTF-8 -Xms1024m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m

可是這不是根本解決之道:apache

  • 首先,Heap也不是越大越好,太大了之後GC會損害性能;
  • 其次,內存也是有成本的;
  • 最重要的,OOM有可能意味着系統中存在缺陷,無論Heap加多大,遲早仍是有一天會被用光!

根本解決之道——經過Profilling找到問題根源

OOM一般是因爲內存被不合理的使用,好比:tomcat

  • 查詢數據庫返回大量結果沒有分頁;
  • 讀取大文件到內存中;

可是OOM錯誤不像其它報錯那樣容易排查,由於沒有Stacktrace可供查看。
要找出內存被過分使用的緣由,必須去「看」OOM時JVM Heap中的情況——哪些Class的Object佔用了過多的內存——Profillingjvm

Oracle JDK已經自帶了很好用的Profilling工具:工具

  • JMX監控

    setclasspath.bat中添加
    【set CATALINA_OPTS=-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=1010 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false】
    命令行【jconsole】打開界面,鏈接tomcat進程,遠程端口1010,能夠查看內存水位、線程池等。性能

  • jmap和jvisualvm

jconsole能看到的信息比較有限,沒法排查出耗掉內存的元兇,
還需藉助jmap來把JVM Heap「轉儲」到文件,而後經過jvisualvm來analysis:
當你的服務OOM了,找到jvm進程id,而後命令行【jmap -heap:format=b pid】生成heap.bin;
而後命令行【jvisualvm】打開分析器,加載heap.bin,查看內存狀態,看看是哪一個傢伙把內存吃光了;
以下圖:ParamTreePaymentTerm有3852個實例,消耗了593K的Heap內存:優化

根據問題緣由對應優化代碼,並按照須要給jvm分配相應內存。spa

經常使用 Java Profiling 工具的分析與比較參考http://www.oschina.net/question/12_10515.net

相關文章
相關標籤/搜索