Java內(nèi)存泄露模擬及分析解決方法_圖文_第1頁
Java內(nèi)存泄露模擬及分析解決方法_圖文_第2頁
Java內(nèi)存泄露模擬及分析解決方法_圖文_第3頁
Java內(nèi)存泄露模擬及分析解決方法_圖文_第4頁
Java內(nèi)存泄露模擬及分析解決方法_圖文_第5頁
已閱讀5頁,還剩4頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、e-mail:derwee derweeJava內(nèi)存泄露模擬及分析解決方法1.1 實(shí)踐目標(biāo):1、使用JAVA代碼實(shí)現(xiàn)模擬內(nèi)存溢出2、分析JDK內(nèi)存溢出的原因3、總結(jié)存在bug的JAVA編碼實(shí)踐4、總結(jié)JVM優(yōu)化的方法1.2 模擬內(nèi)存溢出:為了方便模擬內(nèi)存,特意把JVM的內(nèi)存參數(shù)指定為更小(我的本本內(nèi)存是8G的)。修改eclipse參數(shù)文件eclipse.ini調(diào)用JVM參數(shù):-vmargs-Xms40m(原始是-Xms40m)-Xmx100m(原始是-Xmx384m)演示JAVA小程序?qū)崿F(xiàn)原理:使用集合類對(duì)象裝載大量的Persion對(duì)象,每次把new出來的對(duì)象加入集合類對(duì)象后,更改對(duì)象的屬性,

2、再從集合類對(duì)象中刪除該對(duì)象。會(huì)出現(xiàn)該刪除的對(duì)象沒有被刪掉,Persion類對(duì)象不斷占用內(nèi)存,導(dǎo)致分配給JVM的內(nèi)存被耗光。package com.derwee.collection.memory;import java.util.*;/* * ClassName: OutOfMemory * Description: 內(nèi)存溢出模擬,提出解決方法 * author yangdw* date 2012-3-25 下午6:58:49 */public class OutOfMemory public static void main(String argsCollection collection

3、= new HashSet(;for(int i=0;i<900000000;i+Persion per = new Persion(i,"yangdw"collection.add(per;/把new出來的對(duì)象加到集合里去per.setName("hundsun"/把剛new出來的對(duì)象的名字改為 hundsun collection.remove(per; /把剛加到集合里的對(duì)象刪除 /System.gc(;/手工調(diào)用垃圾回收器System.out.println("請(qǐng)注意,現(xiàn)在集合對(duì)有persion對(duì)象數(shù)-"+collect

4、ion.size(;package com.derwee.collection.memory;/* * ClassName: Persion * Description: TODO(這里用一句話描述這個(gè)類的作用 * author yangdw * date 2012-3-25 下午8:16:54 */public class Persion public Persion(int id, String name super(;this.id = id; = name;private int id;private String name;public int getId( ret

5、urn id;public void setId(int id this.id = id;public String getName( return name;public void setName(String name = name;Overridepublic int hashCode( final int prime = 31;int result = 1;result = prime * result + id;result = prime * result + (name = null ? 0 : name.hashCode(;return result;Ove

6、rridepublic boolean equals(Object obj if (this = objreturn true;if (obj = nullreturn false;if (getClass( != obj.getClass(return false;Persion other = (Persion obj;ifreturn false;if (name = null if ( != nullreturn false; else ifreturn false;return true;使用JDK監(jiān)控程序進(jìn)行監(jiān)控JDK內(nèi)存,線程情況 。模擬程序沒有運(yùn)行前的JDK

7、內(nèi)存使用情況:運(yùn)行JAVA模擬程序后出現(xiàn):內(nèi)存溢出錯(cuò)誤:Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.HashMap.resize(HashMap.java:462at java.util.HashMap.addEntry(HashMap.java:755at java.util.HashMap.put(HashMap.java:385at java.util.HashSet.add(HashSet.java:200at com.derwee.collec

8、tion.memory.OutOfMemory.main(OutOfMemory.java:201.3 內(nèi)存溢出原因分析:在JDK中內(nèi)存劃分主要分為堆和棧。堆主要存儲(chǔ)對(duì)象和數(shù)組;棧主要存儲(chǔ)JAVA原生類型變量。一般JDK初始化后棧占用大小變化不大。堆內(nèi)存是用戶使用的主要部分,大小變化很大,正常的占用圖應(yīng)該是波浪形的。-Xms:?jiǎn)?dòng)應(yīng)用時(shí),JVM 堆空間的初始大小值。-Xmx:應(yīng)用運(yùn)行中,JVM 堆空間的極限值。為了不消耗擴(kuò)大JVM 堆控件分配的開銷,往往此參數(shù)和-Xms 這個(gè)兩個(gè)值設(shè)為相等。當(dāng)非堆內(nèi)存大小+堆內(nèi)存大小 > JVM 堆空間的極限值。就會(huì)出現(xiàn)java.lang.OutOfMe

9、moryError: Java heap space。解決方法:1、 評(píng)估應(yīng)用程序需要內(nèi)存大小。比如大量大對(duì)象存儲(chǔ)在集合對(duì)象內(nèi),遲遲不處理。應(yīng)該及時(shí)釋放稀有資源2、 釋放方式不合理,以為釋放了,其實(shí)沒有,如上面的演示程序。上面的演示程序中,因?yàn)槭褂昧艘詇ashcode來定位查找的hashset,但對(duì)象的name參與計(jì)算hashcode的值被改變了,最后得到的hashcode變了,并沒有把該刪的對(duì)象刪除(collection.remove(per; /把剛加到集合里的對(duì)象刪除),集合對(duì)象還引用著每一個(gè)剛新生成的對(duì)象,即使手工調(diào)用垃圾回收(System.gc(;/手工調(diào)用垃圾回收器)也是沒有用的。

10、因?yàn)槭止ふ{(diào)用gc方法僅僅是通知JVM而已,至于JVM垃圾回收線程有沒有空,能不能成功回收,gc也管不了。集合對(duì)象長度(collection.size( )說明了內(nèi)存溢出。1.4 大型工程中內(nèi)存溢出排查建議1如果在大型工程里排查內(nèi)存溢出,Jconsole已經(jīng)不是最優(yōu)的工具了。因?yàn)镴console沒有提供細(xì)到對(duì)象級(jí)粒度的監(jiān)控。只能根據(jù)應(yīng)用程序正常狀態(tài)下耗用內(nèi)存量,和在異常狀態(tài)下耗用內(nèi)存量比較,可以明確是否存在內(nèi)存溢出的情況存在。如果已經(jīng)確定待處理的大型應(yīng)用程序存在內(nèi)存溢出問題,要定位到某個(gè)Java對(duì)象,某段Java邏輯代碼,位于某個(gè)Java文件,可以借助JProfiler進(jìn)行對(duì)象級(jí)的跟蹤,接著定位

11、到相關(guān)邏輯代碼塊。如果這部分的工作給非常熟悉這個(gè)應(yīng)用程序的人排查,應(yīng)該可以比較快找出存在邏輯問題的代碼塊。1.5 存在bug的代碼實(shí)踐:其實(shí)造成內(nèi)存溢出,除了物理?xiàng)l件外,往往是代碼bug。上面實(shí)例是public int hashCode(造成的內(nèi)存溢出,可見這個(gè)方法很神奇。在編寫代碼時(shí)往往重寫兩個(gè)方法hashCode和equals。hashCode:當(dāng)在集合類中如HashSet,HashMap,Hashtable中存儲(chǔ)對(duì)象時(shí),要特別注意hashCode的實(shí)現(xiàn),如果得到的哈希碼變了,在哈希集合中是無法定位該對(duì)象的,出現(xiàn)刪除該對(duì)象失敗的情況,最終導(dǎo)致了內(nèi)存溢出了。equals:如果要比較對(duì)象的內(nèi)容

12、,請(qǐng)重寫該方法,因?yàn)槟J(rèn)的java.lang.Object.equals(實(shí)現(xiàn)的是比較對(duì)象的內(nèi)存地址。下面代碼說明了StringBuffer實(shí)現(xiàn)沒有重寫equals方法,但String重寫了equals方法如:Set companys = new HashSet(; companys.add(new StringBuffer(" companys.add(new StringBuffer (" System.out.println(companys.size(;/結(jié)果是2Set companys = new HashSet(; companys.add(new String

13、(" companys.add(new String (" System.out.println(companys.size(;/結(jié)果是1對(duì)于HashSet類是怎么確定一個(gè)對(duì)象是否已經(jīng)存在集合類中呢?根據(jù)Java源碼,HashSet類首先看hashcode方法是否相等,然后看equals方法是否相等。注意:當(dāng)重寫對(duì)象的hashCode和equals,當(dāng)用到哈希集合時(shí)注意不要輕易更改參與哈希碼運(yùn)算的對(duì)象屬性,如person的id和name.1.5.1 equals和hashcode重寫原則 對(duì)equals(應(yīng)該遵循如下要求1 對(duì)稱性:如果x.equals(y返

14、回是“true”,那么y.equals(x也應(yīng)該返回是“true”。2 自反性:x.equals(x必須返回是“true”。3 傳遞性:如果x.equals(y返回是“true”,而且y.equals(z返回是“true”,那么z.equals(x也應(yīng)該返回是“true”。4 任何情況下,x.equals(null,永遠(yuǎn)返回是“false”。5 x.equals(和x不同類型的對(duì)象永遠(yuǎn)返回是“false”。 hashCode(的返回值和equals(的關(guān)系如下1 如果x.equals(y返回“true”,那么x和y的hashCode(必須相等。2 如果x.equals(y返回“f

15、alse”,那么x和y的hashCode(有可能相等,也有可能不等。1.2 基于JVM優(yōu)化開始使用JDK默認(rèn)參數(shù),使用JDK自帶的jconsole連續(xù)觀察內(nèi)存使用情況,線程數(shù),確定基線后,設(shè)置合理的優(yōu)化參數(shù)。根據(jù)實(shí)際情況定制合適的優(yōu)化參數(shù),但不要盲目設(shè)置JVM的優(yōu)化參數(shù),可能會(huì)觸發(fā)JDK未知BUG!-Xms:?jiǎn)?dòng)應(yīng)用時(shí),JVM 堆空間的初始大小值。-Xmx:應(yīng)用運(yùn)行中,JVM 堆空間的極限值。為了不消耗擴(kuò)大JVM 堆控件分配的開銷,往往此參數(shù)和-Xms 這個(gè)兩個(gè)值設(shè)為相等。NewSize:堆中新對(duì)象區(qū)大小。PermSize設(shè)置非堆內(nèi)存初始值,默認(rèn)是物理內(nèi)存的1/64。MaxPermSize:應(yīng)

16、用運(yùn)行中,永久存儲(chǔ)區(qū)的極限值。如:set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m優(yōu)化原則:1、 在JVM中如果98的時(shí)間用于GC且可用的Heap size 不足2的時(shí)候?qū)伋龃水惓P畔ⅰ?、 Heap Size 最大不要超過可用物理內(nèi)存的80,一般的要將-Xms和-Xmx選項(xiàng)設(shè)置為相同,而-Xmn為1/4的-Xmx值。3、 JVM初始分配的內(nèi)存由-Xms指定,默認(rèn)是物理內(nèi)存的1/64;JVM最大分配的內(nèi)存由-Xmx指定,默認(rèn)是物理內(nèi)存的1/4。4、 默認(rèn)空余堆內(nèi)

17、存小于40%時(shí),JVM就會(huì)增大堆直到-Xmx的最大限制;空余堆內(nèi)存大于70%時(shí),JVM會(huì)減少堆直到-Xms的最小限制。因此服務(wù)器一般設(shè)置-Xms、-Xmx相等以避免在每次GC 后調(diào)整堆的大小。5、 內(nèi)存分配大小2GB-3GB(一般來說Windows系統(tǒng)下為1.5G-2G,Linux系統(tǒng)下為2G-3G),而64bit以上的處理器就不會(huì)有限制了。1.2.1 JVM監(jiān)控工具介紹JCONSOLE這是隨著JDK分發(fā)的一個(gè)圖形化JVM監(jiān)控工具,可以觀察到j(luò)ava進(jìn)程的gc,class,內(nèi)存等信息。在主界面中有6大tab頁:1. 概述:有關(guān)堆內(nèi)存使用情況,線程,類加載和CPU使用情況的總體情況,支持時(shí)間范圍查詢2. 內(nèi)存:內(nèi)存的詳細(xì)情況,堆和其他內(nèi)存,支持時(shí)間粒度查詢3. 線程:峰值/活動(dòng)線程、各個(gè)線程的明細(xì)信息、檢測(cè)死鎖4. 類:監(jiān)控加載和卸載的類5. vm摘要:有關(guān)vm的明細(xì)信息6. MBean:當(dāng)前Java程序的MBean的操作支持本地JVM和遠(yuǎn)程JVM監(jiān)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論