本章進入JVM學習的最後一節,此節主要分析的是堆,由於堆是JAVA程序中最經常使用使用到的地方,所以對這個地方有必要進行下細緻的分析特別是OOM,言歸正傳,進入正文。java
1、內存溢出(OOM)的緣由session
在JVM中,有哪些內存區間?
堆溢出
public static void main(String args[]){ ArrayList<byte[]> list=new ArrayList<byte[]>(); for(int i=0;i<1024;i++){ list.add(new byte[1024*1024]); } }
永久區
生成大量的類 public static void main(String[] args) { for(int i=0;i<100000;i++){ CglibBean bean = new CglibBean("geym.jvm.ch3.perm.bean"+i,new HashMap()); } }
Java棧溢出
這裏的棧溢出指,在建立線程的時候,須要爲線程分配棧空間,這個棧空間是向操做系統請求的,若是操做系統沒法給出足夠的空間,就會拋出OOM
public static class SleepThread implements Runnable{ public void run(){ try { Thread.sleep(10000000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String args[]){ for(int i=0;i<1000;i++){ new Thread(new SleepThread(),"Thread"+i).start(); System.out.println("Thread"+i+" created"); } }
直接內存溢出
ByteBuffer.allocateDirect()沒法從操做系統得到足夠的空間
for(int i=0;i<1024;i++){ ByteBuffer.allocateDirect(1024*1024); System.out.println(i); System.gc(); }
2、MAT使用基礎多線程
淺堆(Shallow Heap)與深堆(Retained Heap)
顯示入引用(incoming)和出引用(outgoing)
支配樹eclipse
nMemory Analyzer(MAT)
n基於Eclipse的軟件
nhttp://www.eclipse.org/mat/
淺堆
一個對象結構所佔用的內存大小
–3個int類型以及一個引用類型合計佔用內存3*4+4=16個字節。再加上對象頭的8個字節,所以String對象佔用的空間,即淺堆的大小是16+8=24字節
–對象大小按照8字節對齊
–淺堆大小和對象的內容無關,只和對象的結構有關
深堆
–一個對象被GC回收後,能夠真實釋放的內存大小
–只能經過對象訪問到的(直接或者間接)全部對象的淺堆之和 (支配樹)
能夠看到,全部的Point實例淺堆和深堆的大小都是16字節。而dLine對象,淺堆爲16字節,深堆也是16字節,這是由於dLine對象內的兩個點f和g沒有被設置爲null,所以,即便dLine被回收,f和g也不會被釋放。對象cLine內的引用對象d和e因爲僅在cLine內還存在引用,所以只要cLine被釋放,d和e必然也做爲垃圾被回收,即d和e在cLine的保留集內,所以cLine的深堆爲16*2+16=48字節。
對於aLine和bLine對象,因爲二者均持有對方的一個點,所以,當aLine被回收時,公共點a在bLine中依然有引用存在,故不會被回收,點a不在aLine對象的保留集中,所以aLine的深堆大小爲16+16=32字節。對象bLine與aLine徹底一致。
3、使用Visual VM分析堆jvm
– java自帶的多功能分析工具,能夠用來分析堆Dump工具
類的柱狀圖 ,顯示對象數量,總大小等:學習
從類試圖切換到實例試圖,顯示全部的實例:spa
使用OQL查詢:操作系統
返回引用了(0,0)這個點的全部對象線程
4、Tomcat OOM分析案例
Tomcat 在接收大量請求時發生OOM,獲取堆Dump文件,進行分析。
若是是session過多引發OOM
– OOM因爲保存session過多引發,能夠考慮增長堆大小
– 若是應用容許,縮短session的過時時間,使得session能夠及時過時,並回收
PS:具體的分析邏輯太長,此處不作詳細介紹,能夠參考附件。
感謝你們的學習,thank you ! 後面將進入多線程學習系列,敬請關注。
參考文獻:
葛一鳴《深刻JVM內核》視頻學習