深入理解Java虛擬機---(3)內存溢出與內存泄漏

寫在前面:

    內存溢出和內存泄漏都是程序中,我們要極力避免出現的異常,二者在字面上看上去相似,但實際上是不一樣的異常情況,在這篇博客中,我們會總結內存溢出與內存泄漏的區別。

內存溢出和內存泄漏的定義:

    內存溢出:Out Of Memory,指程序在申請內存時,沒有足夠的內存空間供其使用。

    內存泄漏:是指程序在申請內存後,無法釋放已申請的內存空間。

    用通俗一點的話來解釋,內存溢出類似於數組索引越界,超出了數組存儲的上限。內存泄漏是指內存使用完畢後,不能釋放內存,並回收使用。

內存溢出和內存泄漏所導致的結果:

    內存溢出時,程序將會終止,並且拋出Java.lang.OutOfMemoryError異常

    內存泄漏時,程序並不會立刻終止,但是效率會降低,直到沒有剩餘內存,最終也會導致內存溢出。

內存溢出的類型:

    (1)Java堆溢出

    Java堆用於存儲堆實例,不斷的創建對象,那麼在對象數量到達最大堆限制時,就會產生內存溢出。

    (2)虛擬機棧和本地方法棧溢出

    如果線程請求的棧深度大於虛擬機所允許的最大深度,將拋出StackOverflowError 異常。 
    如果虛擬機在擴展棧時無法申請到足夠的內存空間,則拋出OutOfMemoryError異常。

public class JavaVMStackSOF {
		private int stackLength = 1;

		public void stackLeak() {
			stackLength++;// 累加變量
			stackLeak();// 調用自身
		}
	}
    上述代碼是在單線程中調試,程序會報StackOverflowError 異常。 而如果是於多線程之中,程序不斷增加線程,並且爲每一個線程擴大內存,則會報OutOfMemoryError異常。

    (3)方法區和運行時常量池溢出

    運行時常量池是方法區的一部分。方法區用於存放的Class信息,如類名,訪問修飾符,常量池,字段描述,方法描述等。

    對於非-常量池部分,運行時生成大量的動態類填滿方法區。

    對於常量池部分,如果無限循環調用String的intern()方法產生不同的String對象實例,並在List中保存其引用,以防止被GC回收,最終會產生內存溢出。

    (4)本機直接內存溢出

    而此類內存溢出一個明顯的特徵是在Heap Dump文件中不會看見明顯的異常,如果發現OOM之後Dump文件很小,而程序中又直接或間接使用了NIO,可以考慮一下是不是這方面原因。 

    注:在JDK1.4之後加入了NIO,引入了一種基於通道與緩衝區的I/O方式。





    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章