JVM內(nèi)存溢出和內(nèi)存泄漏的區(qū)別及說(shuō)明
1、概念的區(qū)分
1.1、 內(nèi)存泄露(memory leak)
程序運(yùn)行結(jié)束后,沒(méi)有釋放 所占用的內(nèi)存空間。
一次內(nèi)存泄漏 似乎不會(huì)有大的影響,但內(nèi)存泄漏 不斷累積,最終可用內(nèi)存會(huì)變得越來(lái)越少。
比如說(shuō),總內(nèi)存大小是100 MB,有40MB的內(nèi)存一直無(wú)法回收,那么可用的只有60MB 。這40MB的就是內(nèi)存泄漏。
內(nèi)存泄漏,就是程序運(yùn)行結(jié)束后,沒(méi)有釋放的內(nèi)存。
1.2、內(nèi)存溢出(out of memory)
程序運(yùn)行時(shí),在申請(qǐng)內(nèi)存空間時(shí),沒(méi)有足夠的內(nèi)存空間供其正常使用,程序運(yùn)行停止,并拋出 out of memory 。
比如程序運(yùn)行時(shí)申請(qǐng)了一個(gè)10MB 空間, 但是當(dāng)前可用內(nèi)存只有5MB,程序無(wú)法正常執(zhí)行,這就是內(nèi)存溢出。
內(nèi)存溢出 ,可以理解為程序運(yùn)行需要的內(nèi)存大于當(dāng)前可用的內(nèi)存。
1.3 舉例
(1)單例模式中,單例的生命周期和應(yīng)用程序是一樣長(zhǎng)的,所以單例程序中如果持有對(duì)外部對(duì)象的引用的話,那么這個(gè)外部對(duì)象是不能被回收的,則會(huì)導(dǎo)致 內(nèi)存泄露 的產(chǎn)生。
(2)一些提供close的資源未閉導(dǎo)致 內(nèi)存泄漏 。數(shù)據(jù)庫(kù)連接(dataSource.getConnection() ),網(wǎng)絡(luò)連接(socket)和 IO流的連接必須在finally中 close,否則不能被回收的。
(3)讀取大文件,一次讀取的文件大于可用內(nèi)存,會(huì)導(dǎo)致 內(nèi)存溢出 ??捎脙?nèi)存是1G,怎么讀取2G的文件呢?建一個(gè)100MB的字節(jié)數(shù)組,讀10次。
2、二者的區(qū)別和聯(lián)系
2.1 區(qū)別
內(nèi)存泄露: 程序運(yùn)行結(jié)束后,所占用的內(nèi)存沒(méi)有全部釋放。
內(nèi)存溢出:程序運(yùn)行時(shí),需要的內(nèi)存大于當(dāng)前可用的內(nèi)存,內(nèi)存不足,程序無(wú)法繼續(xù)執(zhí)行,拋出 “內(nèi)存溢出”,程序運(yùn)行中斷,結(jié)束。
2.2 聯(lián)系
一次 內(nèi)存泄露 可能對(duì)程序運(yùn)行沒(méi)有明顯的影響,多次 內(nèi)存泄露 最終會(huì)導(dǎo)致 內(nèi)存溢出 。
比如總內(nèi)存大小是100MB,一次程序運(yùn)行結(jié)束有,有10MB 沒(méi)有釋放,當(dāng)前可用內(nèi)存還有90MB,程序還可以運(yùn)行。但是多次運(yùn)行后, 可用內(nèi)存 最終為0, 沒(méi)有可以內(nèi)存或內(nèi)存不足時(shí),程序在下一次運(yùn)行時(shí),會(huì)因?yàn)閮?nèi)存不足,而出現(xiàn) 內(nèi)存溢出 。
3、內(nèi)存溢出的原因以及解決方法
3.1 內(nèi)存溢出的原因
引起內(nèi)存溢出的原因有很多種,小編列舉一下常見的有以下幾種:
- 內(nèi)存中加載的數(shù)據(jù)量過(guò)于龐大,如一次從數(shù)據(jù)庫(kù)取出過(guò)多數(shù)據(jù);
- 集合類中有對(duì)對(duì)象的引用,使用完后未清空,使得JVM不能回收;
- 代碼中存在死循環(huán)或循環(huán)產(chǎn)生過(guò)多重復(fù)的對(duì)象實(shí)體;
- 使用的第三方軟件中的BUG;啟動(dòng)參數(shù)內(nèi)存值設(shè)定的過(guò)小 。
3.2 內(nèi)存溢出的解決方案
第一步,修改JVM啟動(dòng)參數(shù),直接增加內(nèi)存。(-Xms、-Xmx 參數(shù)一定不要忘記加)
第二步,檢查錯(cuò)誤日志,查看 “OutOfMemory” 錯(cuò)誤前是否有其它異?;蝈e(cuò)誤。
第三步,對(duì)代碼進(jìn)行走查和分析,找出可能發(fā)生內(nèi)存溢出的位置。
重點(diǎn)排查以下幾點(diǎn):
1.檢查對(duì)數(shù)據(jù)庫(kù)查詢中,是否有一次獲得全部數(shù)據(jù)的查詢。
- 一般來(lái)說(shuō),如果一次取十萬(wàn)條記錄到內(nèi)存,就可能引起內(nèi)存溢出。
- 這個(gè)問(wèn)題比較隱蔽,在上線前,數(shù)據(jù)庫(kù)中數(shù)據(jù)較少,不容易出問(wèn)題,上線后,
- 數(shù)據(jù)庫(kù)中數(shù)據(jù)多了,一次查詢就有可能引起內(nèi)存溢出。因此對(duì)于數(shù)據(jù)庫(kù)查詢盡量采用分頁(yè)的方式查詢。
2.檢查代碼中是否有死循環(huán)或遞歸調(diào)用。
3.檢查是否有大循環(huán)重復(fù)產(chǎn)生新對(duì)象實(shí)體。
4.檢查對(duì)數(shù)據(jù)庫(kù)查詢中,是否有一次獲得全部數(shù)據(jù)的查詢。
- 一般來(lái)說(shuō),如果一次取十萬(wàn)條記錄到內(nèi)存,就可能引起內(nèi)存溢出。
- 這個(gè)問(wèn)題比較隱蔽,在上線前,數(shù)據(jù)庫(kù)中數(shù)據(jù)較少,不容易出問(wèn)題,
- 上線后,數(shù)據(jù)庫(kù)中數(shù)據(jù)多了,一次查詢就有可能引起內(nèi)存溢出。因此對(duì)于數(shù)據(jù)庫(kù)查詢盡量采用分頁(yè)的方式查詢。
5.檢查L(zhǎng)ist、MAP等集合對(duì)象是否有使用完后,未清除的問(wèn)題。
List、MAP等集合對(duì)象會(huì)始終存有對(duì)對(duì)象的引用,使得這些對(duì)象不能被GC回收。
第四步,使用內(nèi)存查看工具動(dòng)態(tài)查看內(nèi)存使用情況。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot中并發(fā)定時(shí)任務(wù)的實(shí)現(xiàn)、動(dòng)態(tài)定時(shí)任務(wù)的實(shí)現(xiàn)(看這一篇就夠了)推薦
這篇文章主要介紹了SpringBoot并發(fā)定時(shí)任務(wù)動(dòng)態(tài)定時(shí)任務(wù)實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Java中BeanUtils.copyProperties的11個(gè)坑總結(jié)
我們?nèi)粘i_發(fā)中,經(jīng)常涉及到DO、DTO、VO對(duì)象屬性拷貝賦值,很容易想到org.springframework.beans.BeanUtils的copyProperties,它會(huì)自動(dòng)通過(guò)反射機(jī)制獲取源對(duì)象和目標(biāo)對(duì)象的屬性,pyProperties,會(huì)有好幾個(gè)坑呢,本文將給大家總結(jié)一下遇到的坑,需要的朋友可以參考下2023-05-05BeanUtils.copyProperties()所有的空值不復(fù)制問(wèn)題
這篇文章主要介紹了BeanUtils.copyProperties()所有的空值不復(fù)制問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Java?Thread.currentThread().getName()?和?this.getName()區(qū)別詳
本文主要介紹了Thread.currentThread().getName()?和?this.getName()區(qū)別詳解,TestThread?testThread?=?new?TestThread();2022-02-02使用XSD校驗(yàn)Mybatis的SqlMapper配置文件的方法(1)
這篇文章以前面對(duì)SqlSessionFactoryBean的重構(gòu)為基礎(chǔ),簡(jiǎn)單的介紹了相關(guān)操作知識(shí),然后在給大家分享使用XSD校驗(yàn)Mybatis的SqlMapper配置文件的方法,感興趣的朋友參考下吧2016-11-11springBoot的事件機(jī)制GenericApplicationListener用法解析
這篇文章主要介紹了springBoot的事件機(jī)制GenericApplicationListener用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值的相關(guān)資料2019-09-09如何使用@Slf4j和logback-spring.xml搭建日志框架
這篇文章主要介紹了如何使用@Slf4j和logback-spring.xml搭建日志框架問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06