摘要:內(nèi)存溢出分配的內(nèi)存空間超過系統(tǒng)內(nèi)存。內(nèi)存泄漏的原因分析由大塊組成堆,棧,本地方法棧,程序計(jì)數(shù)器,方法區(qū)。內(nèi)存溢出的原因分析內(nèi)存溢出是由于沒被引用的對(duì)象垃圾過多造成沒有及時(shí)回收,造成的內(nèi)存溢出。小結(jié)棧內(nèi)存溢出程序所要求的棧深度過大導(dǎo)致。
前言:JVM中除了程序計(jì)數(shù)器,其他的區(qū)域都有可能會(huì)發(fā)生內(nèi)存溢出。0.什么是內(nèi)存溢出
當(dāng)程序需要申請(qǐng)內(nèi)存的時(shí)候,由于沒有足夠的內(nèi)存,此時(shí)就會(huì)拋出OutOfMemoryError,這就是內(nèi)存溢出。
1.內(nèi)存泄漏和內(nèi)存溢出區(qū)別與聯(lián)系內(nèi)存泄漏:系統(tǒng)分配的內(nèi)存沒有被回收。
內(nèi)存溢出:分配的內(nèi)存空間超過系統(tǒng)內(nèi)存。
2.內(nèi)存泄漏的原因分析jvm由5大塊組成:堆,棧,本地方法棧,程序計(jì)數(shù)器,方法區(qū)。棧它的主要記錄方法的執(zhí)行和對(duì)象的引用。堆則存在真正的引用的對(duì)象。
內(nèi)存泄漏是由于使用不當(dāng),把一部分內(nèi)存“丟掉了”,導(dǎo)致這部分內(nèi)存不可用。
當(dāng)在堆中創(chuàng)建了對(duì)象,后來沒有使用這個(gè)對(duì)象了,又沒有把整個(gè)對(duì)象的相關(guān)引用設(shè)為null。此時(shí)垃圾收集器會(huì)認(rèn)為這個(gè)對(duì)象是需要的,就不會(huì)清理這部分內(nèi)存。這就會(huì)導(dǎo)致這部分內(nèi)存不可用。
所以內(nèi)存泄漏會(huì)導(dǎo)致可用的內(nèi)存減少,進(jìn)而會(huì)導(dǎo)致內(nèi)存溢出。
3. JVM垃圾回收機(jī)制思想就是從棧出發(fā)(root),遍歷對(duì)象的引用,在遍歷堆里面的引用對(duì)象,因?yàn)闂V械膶?duì)象的引用執(zhí)行完畢就刪除,所以我們就可以通過棧中的對(duì)象的引用,查找到堆中沒有被指向的對(duì)象,這些對(duì)象即為不可到達(dá)對(duì)象,對(duì)其進(jìn)行垃圾回收。
4.內(nèi)存溢出的原因分析內(nèi)存溢出是由于沒被引用的對(duì)象(垃圾)過多造成JVM沒有及時(shí)回收,造成的內(nèi)存溢出。如果出現(xiàn)這種現(xiàn)象可行代碼排查:
是否App中的類中和引用變量過多使用了Static修飾 如public staitc Student s;在類中的屬性中使用
static修飾的最好只用基本類型或字符串。如public static int i = 0; //public static
String str;
是否App中使用了大量的遞歸或無限遞歸(遞歸中用到了大量的建新的對(duì)象)
是否App中使用了大量循環(huán)或死循環(huán)(循環(huán)中用到了大量的新建的對(duì)象)
檢查App中是否使用了向數(shù)據(jù)庫查詢所有記錄的方法。即一次性全部查詢的方法,如果數(shù)據(jù)量超過10萬多條了,就可能會(huì)造成內(nèi)存溢出。所以在查詢時(shí)應(yīng)采用“分頁查詢”。
檢查是否有數(shù)組,List,Map中存放的是對(duì)象的引用而不是對(duì)象,因?yàn)檫@些引用會(huì)讓對(duì)應(yīng)的對(duì)象不能被釋放。會(huì)大量存儲(chǔ)在內(nèi)存中。
檢查是否使用了“非字面量字符串進(jìn)行+”的操作。因?yàn)镾tring類的內(nèi)容是不可變的,每次運(yùn)行"+"就會(huì)產(chǎn)生新的對(duì)象,如果過多會(huì)造成新String對(duì)象過多,從而導(dǎo)致JVM沒有及時(shí)回收而出現(xiàn)內(nèi)存溢出。
如:
String s1 = "My name"; String s2 = "is"; String s3 = "xiaomanong"; String str = s1 + s2 + s3 +.........;
這是會(huì)容易造成內(nèi)存溢出的
但是String str = "My name" + " is " + " xuwei" + " nice " + " to " + " meet you"; //但是這種就不會(huì)造成內(nèi)存溢出。因?yàn)檫@是”字面量字符串“,在運(yùn)行"+"時(shí)就會(huì)在編譯期間運(yùn)行好。不會(huì)按照J(rèn)VM來執(zhí)行的。
在使用String,StringBuffer,StringBuilder時(shí),如果是字面量字符串進(jìn)行"+"時(shí),應(yīng)選用String性能更好;如果是String類進(jìn)行"+"時(shí),在不考慮線程安全時(shí),應(yīng)選用StringBuilder性能更好。
5.常見的四種內(nèi)存溢出情況堆溢出(OutOfMemoryError:java heap space)
持久代溢出(OutOfMemoryError: PermGen space)
棧溢出(StackOverflowError)
OutOfMemoryError:unable to create native thread
1)堆溢出:JVM Heap :java.lang.OutOfMemoryError: Java heap space
JVM在啟動(dòng)的時(shí)候會(huì)自動(dòng)設(shè)置JVM Heap的值, 可以利用JVM提供的-Xmn -Xms -Xmx等選項(xiàng)可進(jìn)行設(shè)置。Heap的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的時(shí)間是用于GC,且可用的Heap size 不足2%的時(shí)候?qū)伋龃水惓P畔ⅰ?/p>
解決方法 :手動(dòng)設(shè)置JVM Heap(堆)的大小。
2)持久代溢出:PermGen space : java.lang.OutOfMemoryError: PermGen space
PermGen space的全稱是Permanent Generation space,是指內(nèi)存的永久保存區(qū)域。為什么會(huì)內(nèi)存溢出,這是由于這塊內(nèi)存主要是被JVM存放Class和Meta信息的,Class在被Load的時(shí)候被放入PermGen space區(qū)域,它和存放Instance的Heap區(qū)域不同,sun的 GC不會(huì)在主程序運(yùn)行期對(duì)PermGen space進(jìn)行清理,所以如果你的APP會(huì)載入很多CLASS的話,就很可能出現(xiàn)PermGen space溢出。一般發(fā)生在程序的啟動(dòng)階段。
解決方法 : 通過-XX:PermSize和-XX:MaxPermSize設(shè)置永久代大小即可。
3)棧溢出: java.lang.StackOverflowError : Thread Stack space
棧溢出了,JVM依然是采用棧式的虛擬機(jī),這個(gè)和C和Pascal都是一樣的。函數(shù)的調(diào)用過程都體現(xiàn)在堆棧和退棧上了。調(diào)用構(gòu)造函數(shù)的 “層”太多了,以致于把棧區(qū)溢出了。 通常來講,一般棧區(qū)遠(yuǎn)遠(yuǎn)小于堆區(qū)的,因?yàn)楹瘮?shù)調(diào)用過程往往不會(huì)多于上千層,而即便每個(gè)函數(shù)調(diào)用需要 1K的空間(這個(gè)大約相當(dāng)于在一個(gè)C函數(shù)內(nèi)聲明了256個(gè)int類型的變量),那么棧區(qū)也不過是需要1MB的空間。通常棧的大小是1-2MB的。通俗一點(diǎn)講就是單線程的程序需要的內(nèi)存太大了。 通常遞歸也不要遞歸的層次過多,很容易溢出。
解決方法 :1:修改程序。2:通過 -Xss: 來設(shè)置每個(gè)線程的Stack大小即可。
4)OutOfMemoryError:unable to create native thread
OutOfMemoryError:unable to create native thread:字面意思是內(nèi)存溢出:無法創(chuàng)建新的線程。字面意思已經(jīng)很明顯了,出現(xiàn)這種情況的原因基本下面2點(diǎn):
程序創(chuàng)建的線程數(shù)超過操作系統(tǒng)的限制。
JVM占用的內(nèi)存太多,導(dǎo)致創(chuàng)建線程的內(nèi)存空間太小。
我們都知道操作系統(tǒng)對(duì)每個(gè)進(jìn)程的內(nèi)存是有限制的,我們啟動(dòng)Jvm,相當(dāng)于啟動(dòng)了一個(gè)進(jìn)程,假如我們一個(gè)進(jìn)程占用了4G的內(nèi)存,那么通過下面的公式計(jì)算出來的剩余內(nèi)存就是建立線程棧的時(shí)候可以用的內(nèi)存。 線程??偪捎脙?nèi)存=4G-(-Xmx的值)- (-XX:MaxPermSize的值)- 程序計(jì)數(shù)器占用的內(nèi)存 通過上面的公式我們可以看出,-Xmx 和 MaxPermSize的值越大,那么留給線程??捎玫目臻g就越小,在-Xss參數(shù)配置的棧容量不變的情況下,可以創(chuàng)建的線程數(shù)也就越小。因此如果是因?yàn)檫@種情況導(dǎo)致的unable to create native thread,
解決方法:1:增大進(jìn)程所占用的總內(nèi)存。2:減少-Xmx或者-Xss來達(dá)到創(chuàng)建更多線程的目的。
5)小結(jié)
棧內(nèi)存溢出:程序所要求的棧深度過大導(dǎo)致。
堆內(nèi)存溢出: 分清 內(nèi)存泄露還是 內(nèi)存容量不足。泄露則看對(duì)象如何被 GC Root 引用。不足則通過 調(diào)大 -Xms,-Xmx參數(shù)。
持久帶內(nèi)存溢出:Class對(duì)象未被釋放,Class對(duì)象占用信息過多,有過多的Class對(duì)象。
無法創(chuàng)建本地線程:總?cè)萘坎蛔?,堆?nèi)存,非堆內(nèi)存設(shè)置過大,會(huì)導(dǎo)致能給線程的內(nèi)存不足。
下面哪種情況會(huì)導(dǎo)致持久區(qū)jvm堆內(nèi)存溢出():
A. 循環(huán)上萬次的字符串處理
B. 在一段代碼內(nèi)申請(qǐng)上百M(fèi)甚至上G的內(nèi)存
C. 使用CGLib技術(shù)直接操作字節(jié)碼運(yùn)行,生成大量的動(dòng)態(tài)類
D. 不斷創(chuàng)建對(duì)象
解答:AC
解析:AC是持久帶,B直接內(nèi)存也就是堆外內(nèi)存,D堆內(nèi)存。
參考書籍:《深入理解Java虛擬機(jī)》 (第二版) 周志明 著;
溫馨提示: 如果你喜歡本文,并且想要學(xué)習(xí)更多干貨內(nèi)容,可以關(guān)注一下我的公眾號(hào)《Java技術(shù)zhai》;
不定期的技術(shù)干貨內(nèi)容分享,帶你重新理解架構(gòu)的魅力!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/76057.html
摘要:從使用到原理學(xué)習(xí)線程池關(guān)于線程池的使用,及原理分析分析角度新穎面向切面編程的基本用法基于注解的實(shí)現(xiàn)在軟件開發(fā)中,分散于應(yīng)用中多出的功能被稱為橫切關(guān)注點(diǎn)如事務(wù)安全緩存等。 Java 程序媛手把手教你設(shè)計(jì)模式中的撩妹神技 -- 上篇 遇一人白首,擇一城終老,是多么美好的人生境界,她和他歷經(jīng)風(fēng)雨慢慢變老,回首走過的點(diǎn)點(diǎn)滴滴,依然清楚的記得當(dāng)初愛情萌芽的模樣…… Java 進(jìn)階面試問題列表 -...
摘要:而字節(jié)碼運(yùn)行在之上,所以不用關(guān)心字節(jié)碼是在哪個(gè)操作系統(tǒng)編譯的,只要符合規(guī)范,那么,這個(gè)字節(jié)碼文件就是可運(yùn)行的。好處防止內(nèi)存中出現(xiàn)多份同樣的字節(jié)碼安全性角度特別說明類加載器在成功加載某個(gè)類之后,會(huì)把得到的類的實(shí)例緩存起來。 前言 只有光頭才能變強(qiáng) JVM在準(zhǔn)備面試的時(shí)候就有看了,一直沒時(shí)間寫筆記。現(xiàn)在到了一家公司實(shí)習(xí),閑的時(shí)候就寫寫,刷刷JVM博客,刷刷電子書。 學(xué)習(xí)JVM的目的也很簡(jiǎn)單...
摘要:方法區(qū)溢出在的方法區(qū)中,它主要存放了類的信息,常量,靜態(tài)變量等。運(yùn)行結(jié)果簡(jiǎn)單解決思路一般來說此類問題多出現(xiàn)在存在遞歸的地方,要從代碼里重新審視遞歸未結(jié)束的原因,若遞歸的方法沒問題可以根據(jù)實(shí)際情況調(diào)整參數(shù)的大小。 前言 如今不管是在面試還是在我們的工作中,OOM總是不斷的出現(xiàn)在我們的視野中,所以我們有必要去了解一下導(dǎo)致OOM的原因以及一些基本的調(diào)整方法,大家可以通過下面的事例來了解一下什...
閱讀 1150·2021-11-22 14:56
閱讀 1614·2019-08-30 15:55
閱讀 3445·2019-08-30 15:45
閱讀 1709·2019-08-30 13:03
閱讀 2934·2019-08-29 18:47
閱讀 3402·2019-08-29 11:09
閱讀 2715·2019-08-26 18:36
閱讀 2663·2019-08-26 13:55