JVM内存溢出分析-实战JVM(二)
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
JVM規(guī)范規(guī)定,除了程序計數(shù)器,虛擬機(jī)其他內(nèi)存區(qū)域均會發(fā)生內(nèi)存溢出的可能,OutOfMemoryError(OOM)
原文地址:http://www.begincode.net/blog/62? 我的網(wǎng)站,歡迎大家多提意見
本文目的:
? ? 1、通過代碼人為造成OOM,讓大家跟了解JVM運行時各區(qū)存儲的內(nèi)容。
? ? 2、通過demo讓大家實際開發(fā)過程中,能夠根據(jù)異常判斷是那個內(nèi)存區(qū)域發(fā)生的溢出,
? ? 3、讓大家了解到什么樣的代碼會產(chǎn)生OOM,開發(fā)中能夠盡量規(guī)避。
前提:
?? ? 先和大家介紹一下eclipse如何設(shè)置JVM參數(shù),Xms 最小堆內(nèi)存,Xmx最大堆內(nèi)存,
? ? ??HeapDumpOnOutOfMemoryError:發(fā)生內(nèi)存溢出時生成堆轉(zhuǎn)儲快照
一、JAVA堆內(nèi)存溢出
?代碼實例,來自<<深入理解JVM虛擬機(jī)>>
public class TestOOM {static class OOMObject{}public static void main(String[] args) {List<OOMObject> list = new ArrayList<OOMObject>();while(true){list.add(new OOMObject());}}}運行結(jié)果如下,發(fā)生內(nèi)存溢出,在OutOfMemoryError后面會跟著 Java heap space 提示是堆內(nèi)存溢出,
同時生成?java_pid10308.hprof 文件
該文件可以用分析工具M(jìn)AT進(jìn)行分析,安裝鏈接http://www.begincode.net/blog/45?也可以用其他工具,
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid10308.hprof ... Heap dump file created [27883798 bytes in 0.497 secs]通過工具可以分析是內(nèi)存泄露還是內(nèi)存溢出,如果不存在泄露,那就是存在著很多對象實例無法回收,可以通過分析查看是那些對象,是否必須存活,如果必須存活在考慮適當(dāng)調(diào)整JVM堆參數(shù),如Xmx Xms等在以后的文章中會在此介紹。
二、虛擬機(jī)棧和本地方棧溢出(棧溢出)
? ? 1、虛擬機(jī)棧
? ?虛擬機(jī)棧溢出,理論上分為兩種,一種是線程請求的棧深度大于虛擬機(jī)允許的最大深度,另外一種是申請的空間不足。
? ?因為虛擬機(jī)棧記錄的是局部變量(方法變量)和函數(shù)調(diào)用棧針,則產(chǎn)生堆棧溢出一般是函數(shù)調(diào)用深度,如遞歸類或者
? ? 方法A調(diào)用方法B,方法B調(diào)用方法C這樣調(diào)用深度超過了虛擬機(jī)允許的最大深度,
? ? JVM參數(shù)設(shè)置為如下,Xss128k ?Xss是堆棧大小
-Xms20m -Xmx20m -Xss128k -XX:+HeapDumpOnOutOfMemoryError?demo如下
public class TestOOM {static int stackIndex = 0;public void testStackOverFlow(){stackIndex++;testStackOverFlow();}public static void main(String[] args) throws Throwable {try{TestOOM oom = new TestOOM();oom.testStackOverFlow();}catch(Throwable e){System.out.println("堆棧深度(迭代次數(shù)):"+stackIndex);throw e;}} }執(zhí)行結(jié)果,堆棧深度達(dá)到983,堆棧溢出,并會給出具體是類,方法,發(fā)生的錯誤
堆棧深度(迭代次數(shù)):983 Exception in thread "main" java.lang.StackOverflowErrorat zgwx.TestOOM.testStackOverFlow(TestOOM.java:9)at zgwx.TestOOM.testStackOverFlow(TestOOM.java:10) 相同參數(shù)情況下如果修改遞歸的方法,在方法內(nèi)創(chuàng)建幾個變量大家再看下結(jié)果。 public void testStackOverFlow(){stackIndex++;int str = 12;int str2 = 12;int str3 = 12;int str4 = 12;int str5 = 12;int str6 = 12;int str7 = 12;int str8 = 12;testStackOverFlow();}執(zhí)行結(jié)果如下,迭代次數(shù)明顯減少,說明局部變量占用了堆棧的空間
堆棧深度(迭代次數(shù)):579 Exception in thread "main" java.lang.StackOverflowErrorat zgwx.TestOOM.testStackOverFlow(TestOOM.java:9)at zgwx.TestOOM.testStackOverFlow(TestOOM.java:18)? ? 2、本地方法棧,本地方法棧可以通過創(chuàng)建線程的方式來實現(xiàn)溢出,因為java線程是映射到操作系統(tǒng)內(nèi)核上,所以線程會調(diào)用本地方法,造成本地方法棧的溢出
? ?本機(jī)環(huán)境沒測試出來,機(jī)器卡死了,大家可以自己試試盡量多創(chuàng)建線程,就會撐爆本地方法棧
? ?下面是找來的例子,沒見到效果,都死卡死機(jī)告終
public class Test {private void runAlways(){while(true){}}public void createThread(){while(true){Thread thread = new Thread(new Runnable(){public void run() {runAlways();}});thread.start();}}public static void main(String[] args) {Test test = new Test();test.createThread();}}三、直接本機(jī)內(nèi)存溢出
? ? 本機(jī)內(nèi)存溢出可以無限制申請空間即可,用nio的申請緩沖區(qū)方式
public static void main(String[] args) {List list = new ArrayList();while(true){ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024*2048);list.add(byteBuffer);}}執(zhí)行結(jié)果如下,OutOfMemoryError后面的提示,Direct buffer memory 說明了直接緩沖區(qū),
Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memoryat java.nio.Bits.reserveMemory(Bits.java:658)at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)四、方法區(qū)(永久代)溢出
? ? 方法區(qū)存儲的是加載的類信息,常量,我們就循環(huán)創(chuàng)建字符串常量,讓方法區(qū)溢出
? ? 為了盡快溢出,jvm參數(shù)設(shè)置永久代參數(shù)5M: -XX:PermSize=5m ?-XX:MaxPermSize=5m
? ? 代碼如下:
public static void main(String[] args) {List list = new ArrayList();int i = 0;while(true){list.add((String.valueOf(i++)).intern());}}?運行結(jié)果如下:OutOfMemoryError后面提示 PermGen space ;改代碼在jdk6及以下版本能夠報出如下異常,jdk7高版本及以上部分jvm已經(jīng)逐漸開始取消永久代的原因,只會報出堆內(nèi)存異常
Exception in thread "main" java.lang.OutOfMemoryError: PermGen spaceat java.lang.String.intern(Native Method)at com.TestSocket.main(TestSocket.java:12)轉(zhuǎn)載于:https://my.oschina.net/UpBoy/blog/514926
總結(jié)
以上是生活随笔為你收集整理的JVM内存溢出分析-实战JVM(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS 简简单单构造单例
- 下一篇: jquery.validation.js