jvm內(nèi)存溢

1 前言

相信有一定java開發(fā)經(jīng)驗的人或多或少都會遇到OutOfMemoryError的問題,這個問題曾困擾了我很長時間,隨著解決各類問題經(jīng)驗的積累以及對問題根源的探索,終于有了一個比較深入的認識。

在解決java內(nèi)存溢出問題之前,需要對jvm(java虛擬機)的內(nèi)存管理有一定的認識。jvm管理的內(nèi)存大致包括三種不同類型的內(nèi)存區(qū)域:Permanent Generation space(永久保存區(qū)域)、Heap space(堆區(qū)域)、Java Stacks(Java棧)。其中永久保存區(qū)域主要存放Class(類)和Meta的信息,Class第一次被Load的時候被放入PermGen space區(qū)域,Class需要存儲的內(nèi)容主要包括方法和靜態(tài)屬性。堆區(qū)域用來存放Class的實例(即對象),對象需要存儲的內(nèi)容主要是非靜態(tài)屬性。每次用new創(chuàng)建一個對象實例后,對象實例存儲在堆區(qū)域中,這部分空間也被jvm的垃圾回收機制管理。而Java棧跟大多數(shù)編程語言包括匯編語言的棧功能相似,主要基本類型變量以及方法的輸入輸出參數(shù)。Java程序的每個線程中都有一個獨立的堆棧。容易發(fā)生內(nèi)存溢出問題的內(nèi)存空間包括:Permanent Generation space和Heap space。

2 第一種OutOfMemoryError: PermGen space

發(fā)生這種問題的原意是程序中使用了大量的jar或class,使java虛擬機裝載類的空間不夠,與Permanent Generation space有關(guān)。解決這類問題有以下兩種辦法:

  1. 增加java虛擬機中的XX:PermSize和XX:MaxPermSize參數(shù)的大小,其中XX:PermSize是初始永久保存區(qū)域大小,XX:MaxPermSize是最大永久保存區(qū)域大小。如針對tomcat6.0,在catalina.sh 或catalina.bat文件中一系列環(huán)境變量名說明結(jié)束處(大約在70行左右) 增加一行:

JAVA_OPTS=" -XX:PermSize=64M -XX:MaxPermSize=128m"

3 第二種OutOfMemoryError: Java heap space

發(fā)生這種問題的原因是java虛擬機創(chuàng)建的對象太多,在進行垃圾回收之間,虛擬機分配的到堆內(nèi)存空間已經(jīng)用滿了,與Heap space有關(guān)。解決這類問題有兩種思路:

  1. 檢查程序,看是否有死循環(huán)或不必要地重復創(chuàng)建大量對象。找到原因后,修改程序和算法。(如果找不到原因,參考5.如何利用工具檢查內(nèi)存泄露)

  2. 增加Java虛擬機中Xms(初始堆大?。┖蚗mx(最大堆大小)參數(shù)的大小。如:set JAVA_OPTS= -Xms256m -Xmx1024m

4 第三種OutOfMemoryError:unable to create new native thread

這種錯誤在Java線程個數(shù)很多的情況下容易發(fā)生,一般有兩種可能:

在程序里面使用了http-client,http-client 有兩個超時參數(shù),但實際只設置了一個參數(shù),然后當對方的服務器宕機之后,httpClient一直處于等待狀態(tài),導致線程堆積。

httpClient-3.0的超時時間設置代碼如下:

httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(10000); //設置連接超時時間

httpClient.getHttpConnectionManager().getParams().setSoTimeout(10000);//當連接上之后,等待對方傳輸數(shù)據(jù)的超時時間(大部分是這個時間忘記設置)

httpClient-4.0的超時時間設置代碼如下:

         HttpPost httpPost = new HttpPost(url);
         RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build();//設置請求和傳輸超時時間

做了多線程,而每個線程的耗時過多導致的(新增線程的速度比處理完成線程的速度快)。這種情況只能通過優(yōu)化程序或者進行集群化部署來解決。

5 如何利用工具檢查JAVA內(nèi)存泄露

巧婦難為無米之炊,當發(fā)生內(nèi)存溢出的時候,我們需要把內(nèi)存堆棧保存下來,之后才能進行分析。具體步驟如下:

5.1 獲取java的內(nèi)存堆棧
5.1.1 windows系統(tǒng)獲取java內(nèi)存堆棧
打開jdk安裝目錄\bin下的 jvisualvm.exe,如下圖:


1586603278(1).jpg

1586603304(1).jpg

1586603333(1).jpg

1586603341(1).jpg
5.1.2 linux系統(tǒng)獲取java內(nèi)存堆棧

1、運行ps -ef|grep java (你的java進程ID )

2、運行: jmap -dump:format=b,file=/usr/local/Client/log20151014.dmp 1186 (其中1186換為你的java的進程ID)

3、之后將log20151014.dmp拷貝到個人電腦上,以便后面分析。

5.2 使用IBM的內(nèi)存泄露分析工具進行分析

5.2.1 IBM-HeapAnalyzer下載地址
http://www.alphaworks.ibm.com/tech/heapanalyzer

1586603506(1).jpg

5.2.1 IBM-HeapAnalyzer初級使用教程
使用javaw打開下載到的ha456.jar,如下圖:


1586603534(1).jpg

(如果出現(xiàn)內(nèi)存不足,無法打開dmp文件的情況,可以打開命令窗口,進入jar 的目錄,然后輸入

java -jar -Xmx3000m ha456.jar)


1586603568(1).jpg

1586603591(1).jpg

1586603609(1).jpg

然后通過搜索查詢相關(guān)資料,排查到是mysql的connector/J官方驅(qū)動存在內(nèi)存泄露,通過更新mysql的jdbc驅(qū)動解決此問題。
原文鏈接:https://blog.csdn.net/xxxx3/java/article/details/81009524

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容