java-内存溢出与内存泄漏
目錄
內(nèi)存溢出(OOM)
內(nèi)存泄漏(Memory?Leak)
內(nèi)存溢出(OOM)
1.內(nèi)存溢出相對(duì)于內(nèi)存泄漏來(lái)說(shuō),盡管更容易被理解,但是同樣的,內(nèi)存溢出也是引發(fā)程序崩潰的罪魁禍?zhǔn)字弧?/p>
2.由于GC一直在發(fā)展,所有一般情況下,除非應(yīng)用程序占用的內(nèi)存增長(zhǎng)速度非???#xff0c;造成垃圾回收已經(jīng)跟不上內(nèi)存消耗的速度,否則不太容易出現(xiàn)OOM的情況。
3.大多數(shù)情況下,GC會(huì)進(jìn)行各種年齡段的垃圾回收,實(shí)在不行了就放大招,來(lái)一次獨(dú)占式的Full?GC操作,這時(shí)候會(huì)回收大量的內(nèi)存,供應(yīng)用程序繼續(xù)使用。
4.javadoc中對(duì)OutOfMemoryError的解釋是,沒(méi)有空閑內(nèi)存,并且垃圾收集器也無(wú)法提供更多內(nèi)存。
5.首先說(shuō)沒(méi)有空閑內(nèi)存的情況:說(shuō)明Java虛擬機(jī)的堆內(nèi)存不夠。原因有二:
(1)Java虛擬機(jī)的堆內(nèi)存設(shè)置不夠。
? ? 比如:可能存在內(nèi)存泄漏問(wèn)題;也很有可能就是堆的大小不合理,比如我們要處理比較可觀的數(shù)據(jù)量,但是沒(méi)有顯式指定JVM堆大小或者指定數(shù)值偏小。我們可以通過(guò)參數(shù)-Xms、-Xmx來(lái)調(diào)整。
(2)代碼中創(chuàng)建了大量大對(duì)象,并且長(zhǎng)時(shí)間不能被垃圾收集器收集(存在被引用)
? ? 對(duì)于老版本的Oracle?JDK,因?yàn)橛谰么拇笮r(shí)有限的,并且JVM對(duì)永久代垃圾回收(如,常量池回收、卸載不再需要的類型)非常不積極,所以當(dāng)我們不斷添加新類型的時(shí)候,永久代出現(xiàn)OutOfMemoryError也非常多見(jiàn),尤其是在運(yùn)行時(shí)存在大量動(dòng)態(tài)類型生成的場(chǎng)合;類似intern字符串緩存占用太多空間,也會(huì)導(dǎo)致OOM問(wèn)題。對(duì)應(yīng)的異常信息,會(huì)標(biāo)記出來(lái)和永久代相關(guān):“java.lang.OutOfMemoryError:PermGen?space”。
? ? 隨著元數(shù)據(jù)區(qū)的引入,方法區(qū)內(nèi)存已經(jīng)不再那么窘迫,所以相應(yīng)的OOM有所改觀,出現(xiàn)OOM,異常信息則變成了:“java.lang.OutOfMemoryError:Metaspace”。直接內(nèi)存不足,也會(huì)導(dǎo)致OOM。
6.這里面隱含著一層意思是,在拋出OutOfMemoryError之前,通常垃圾收集器會(huì)被觸發(fā),盡其所能去清理出空間。
? ? 例如:在引用機(jī)制分析中,涉及到JVM會(huì)去嘗試回收軟引用指向的對(duì)象等。
? ? 在java.nio.BIts.reserveMemory()方法中,我們能清除的看到,System.gc()會(huì)被調(diào)用,以清理空間。
7.當(dāng)然,也不是在任何情況下垃圾收集器都會(huì)被觸發(fā)的。
? ? 比如,我們?nèi)シ峙湟粋€(gè)超大對(duì)象,類似一個(gè)超大數(shù)組超過(guò)堆的最大值,JVM可以判斷出垃圾收集并不能解決這個(gè)問(wèn)題,所以直接拋出OutOfMemoryError。
內(nèi)存泄漏(Memory?Leak)
1.也稱作“存儲(chǔ)滲漏”。嚴(yán)格來(lái)說(shuō),只有對(duì)象不會(huì)再被程序用到了,但是GC又不能回收他們的情況,才叫內(nèi)存泄漏。
2.但實(shí)際情況很多時(shí)候一些不太好的實(shí)踐(或疏忽)會(huì)導(dǎo)致對(duì)象的生命周期變得很長(zhǎng)甚至導(dǎo)致OOM,也可以叫做寬泛意義上的“內(nèi)存泄漏”。
3.盡管內(nèi)存泄漏并不會(huì)立刻引起程序崩潰,但是一旦發(fā)生內(nèi)存泄漏,程序中的可用內(nèi)存就會(huì)被逐步蠶食,直至耗盡所有內(nèi)存,最終出現(xiàn)OutOfMemory異常,導(dǎo)致程序崩潰。
4.注意,這里的存儲(chǔ)空間并不是指物理內(nèi)存,而是指虛擬機(jī)內(nèi)存大小,這個(gè)虛擬內(nèi)存大小取決于磁盤交換區(qū)設(shè)定的大小。
舉例:
1.單例模式
? ? 單例的生命周期和應(yīng)用程序時(shí)一樣長(zhǎng)的,所以單例程序中,如果持有對(duì)外部對(duì)象的引用的話,那么這個(gè)外部對(duì)象是不能被回收的,則會(huì)導(dǎo)致內(nèi)存泄漏的發(fā)生。
2.一些提供close的資源未關(guān)閉導(dǎo)致內(nèi)存泄漏
? ? 數(shù)據(jù)庫(kù)連接(dataSource.getConnection()),網(wǎng)絡(luò)連接(socket)和io連接必須手動(dòng)close,否則是不能被回收的。
?
總結(jié)
以上是生活随笔為你收集整理的java-内存溢出与内存泄漏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java的System.gc()的理解
- 下一篇: 认识java-STW:Stop the