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