JVM內(nèi)存機(jī)制資料筆記
參考
JDK5.0垃圾收集優(yōu)化之--Don't Pause
http://blog.csdn.net/calvinxiu/archive/2007/05/18/1614473.aspx
JVM內(nèi)存模型以及垃圾回收
http://hi.baidu.com/xuwanbest/blog/item/0587d82f2c44a73d1e30892e.html
對(duì)jvm內(nèi)存的一些理解
http://www.blogjava.net/midstr/archive/2008/09/21/230292.html
了解JVM的內(nèi)存管理與垃圾回收
http://hi.baidu.com/jiaozhenqing/blog/item/f18b85d4c1063a07a08bb77e.html
Java內(nèi)存溢出的解決方案
http://hi.baidu.com/yanghlcn/blog/item/029e7303917b528dd43f7cc3.html
Java內(nèi)存組成
?
?
堆(Heap)
??? 運(yùn)行時(shí)數(shù)據(jù)區(qū)域,所有類實(shí)例和數(shù)組的內(nèi)存均從此處分配。Java 虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。對(duì)象的堆內(nèi)存由稱為垃圾回收器 的自動(dòng)內(nèi)存管理系統(tǒng)回收。
??? 組成
??? ???
News Generation
(Young Generation即圖中的Eden + From Space + To Space)
??? ??? ???
Eden
存放新生的對(duì)象
??? ??? ???
Survivor Space
兩個(gè) 存放每次垃圾回收后存活的對(duì)象
??? ???
Old Generation
(Tenured Generation 即圖中的Old Space) 主要存放應(yīng)用程序中生命周期長(zhǎng)的存活對(duì)象
非堆內(nèi)存
???
JVM具有一個(gè)由所有線程共享的方法區(qū)。方法區(qū)屬于非堆內(nèi)存。它存儲(chǔ)每個(gè)類結(jié)構(gòu),如運(yùn)行時(shí)常數(shù)池、字段和方法數(shù)據(jù),以及方法和構(gòu)造方法的代碼。它是在 Java 虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建的。
??? 除了方法區(qū)外,Java 虛擬機(jī)實(shí)現(xiàn)可能需要用于內(nèi)部處理或優(yōu)化的內(nèi)存,這種內(nèi)存也是非堆內(nèi)存。 例如,JIT 編譯器需要內(nèi)存來存儲(chǔ)從 Java 虛擬機(jī)代碼轉(zhuǎn)換而來的本機(jī)代碼,從而獲得高性能。
??? 組成
??? ???
Permanent Generation
?
(圖中的Permanent Space)
存放JVM自己的反射對(duì)象,比如類對(duì)象和方法對(duì)象
??? ???
native heap
GC策略
堆
????? JVM采用一種
分代回收
(generational collection) 的策略,用較高的頻率對(duì)年輕的對(duì)象(young generation)進(jìn)行掃描和回收,這種叫做minor collection,而對(duì)老對(duì)象(old generation)的檢查回收頻率要低很多,稱為major collection。這樣就不需要每次GC都將內(nèi)存中所有對(duì)象都檢查一遍。
????? 當(dāng)一個(gè)URL被訪問時(shí),
內(nèi)存申請(qǐng)過程
如下:
A. JVM會(huì)試圖為相關(guān)Java對(duì)象在Eden中初始化一塊內(nèi)存區(qū)域
B. 當(dāng)Eden空間足夠時(shí),內(nèi)存申請(qǐng)結(jié)束。否則到下一步
C. JVM試圖釋放在Eden中所有不活躍的對(duì)象(這屬于1或更高級(jí)的垃圾回收), 釋放后若Eden空間仍然不足以放入新對(duì)象,則試圖將部分Eden中活躍對(duì)象放入Survivor區(qū)
D. Survivor區(qū)被用來作為Eden及OLD的中間交換區(qū)域,當(dāng)OLD區(qū)空間足夠時(shí),Survivor區(qū)的對(duì)象會(huì)被移到Old區(qū),否則會(huì)被保留在Survivor區(qū)
E. 當(dāng)OLD區(qū)空間不夠時(shí),JVM會(huì)在OLD區(qū)進(jìn)行完全的垃圾收集(0級(jí))
F. 完全垃圾收集后,若Survivor及OLD區(qū)仍然無法存放從Eden復(fù)制過來的部分對(duì)象,導(dǎo)致JVM無法在Eden區(qū)為新對(duì)象創(chuàng)建內(nèi)存區(qū)域,則出現(xiàn)”out of memory錯(cuò)誤”
???
對(duì)象衰老的過程
??? young generation的內(nèi)存,由一塊Eden(伊甸園,有意思)和兩塊Survivor Space(1.4文檔中稱為semi-space)構(gòu)成。新創(chuàng)建的對(duì)象的內(nèi)存都分配自eden。兩塊Survivor Space總有會(huì)一塊是空閑的,用作copying collection的目標(biāo)空間。Minor collection的過程就是將eden和在用survivor space中的活對(duì)象copy到空閑survivor space中。所謂survivor,也就是大部分對(duì)象在伊甸園出生后,根本活不過一次GC。對(duì)象在young generation里經(jīng)歷了一定次數(shù)的minor collection后,年紀(jì)大了,就會(huì)被移到old generation中,稱為tenuring。(是否僅當(dāng)survivor space不足的時(shí)候才會(huì)將老對(duì)象tenuring? 目前資料中沒有找到描述)
??? ?剩余內(nèi)存空間不足會(huì)觸發(fā)GC,如eden空間不夠了就要進(jìn)行minor collection,old generation空間不夠要進(jìn)行major collection,permanent generation空間不足會(huì)引發(fā)full GC。
?
非堆內(nèi)存
????? GC(Garbage Collection)不會(huì)在主程序運(yùn)行期對(duì)PermGen space進(jìn)行清理,所以如果你的應(yīng)用中有很多CLASS的話,就很可能出現(xiàn)PermGen space錯(cuò)誤。
?
?
JVM的默認(rèn)設(shè)置
堆 (heap)(News Generation 和Old Generaion 之和)的設(shè)置
?????? 初始分配的內(nèi)存由-Xms指定,默認(rèn)是物理內(nèi)存的1/64但小于1G。
?????? 最大分配的內(nèi)存由-Xmx指定,默認(rèn)是物理內(nèi)存的1/4但小于1G。
?????? 默認(rèn)空余堆內(nèi)存小于40%時(shí),JVM就會(huì)增大堆直到-Xmx的最大限制,可以由-XX:MinHeapFreeRatio=指定。
默認(rèn)空余堆內(nèi)存大于70%時(shí),JVM會(huì)減少堆直到-Xms的最小限制,可以由-XX:MaxHeapFreeRatio=指定。
服務(wù)器一般設(shè)置-Xms、-Xmx相等以避免在每次GC 后調(diào)整堆的大小,所以上面的兩個(gè)參數(shù)沒啥用。?
?????? -Xmn 設(shè)置young?generation的heap大小
????? -XX:MinHeapFreeRatio與-XX:MaxHeapFreeRatio設(shè)定空閑內(nèi)存占總內(nèi) 存的比例范圍,這兩個(gè)參數(shù)會(huì)影響GC的頻率和單次GC的耗時(shí)。-XX:NewRatio決定young與old generation的比例。Young generation空間越大,minor collection頻率越低,但是old generation空間小了,又可能導(dǎo)致major collection頻率增加。-XX:NewSize和-XX:MaxNewSize直接指定了young generation的缺省大小和最大大小。
?
非堆內(nèi)存 的設(shè)置
???? 默認(rèn)分配為64M
???? -XX:PermSize設(shè)置最小分配空間,-XX:MaxPermSize設(shè)置最大分配空間。一般把這兩個(gè)數(shù)值設(shè)為相同,以減少申請(qǐng)內(nèi)存空間的時(shí)間。
?
?
內(nèi)存溢出 的原 因
Old Generation溢出
這種內(nèi)存溢出是最常見的情況之一,產(chǎn)生的原因可能是:
1) 設(shè)置的內(nèi)存參數(shù)過小(ms/mx, NewSize/MaxNewSize)
??? 解決方法:
???? 1G內(nèi)存環(huán)境下java jvm 的參數(shù)設(shè)置參考:
??? -server -Xms800m -Xmx800m -XX:PermSize=64M -XX:MaxNewSize=256m -XX:MaxPermSize=128m? -Djava.awt.headless=true
2) 程序問題
單個(gè)程序持續(xù)進(jìn)行消耗內(nèi)存的處理,如循環(huán)幾千次的字符串處理,對(duì)字符串處理應(yīng)建議使用StringBuffer。此時(shí)不會(huì)報(bào)內(nèi)存溢出錯(cuò),卻會(huì)使系統(tǒng)持續(xù)垃 圾收集,無法處理其它請(qǐng)求,相關(guān)問題程序可通過Thread Dump獲取。
單個(gè)程序所申請(qǐng)內(nèi)存過大,有的程序會(huì)申請(qǐng)幾十乃至幾百兆內(nèi)存,此時(shí)JVM也會(huì)因無法申請(qǐng)到資源而出現(xiàn)內(nèi)存溢出,對(duì)此首 先要找到相關(guān)功能,然后交予程序員修改,要找到相關(guān)程序,必須在Apache日志中尋找。
當(dāng)Java對(duì)象使用完畢后,其所引用的對(duì)象卻沒有銷毀,使得JVM認(rèn)為他還是活躍的對(duì)象而不進(jìn)行回收,這樣累計(jì)占用了大量?jī)?nèi)存而無法釋放。由于目前市面上還沒有對(duì)系統(tǒng)影響小的內(nèi)存分析工具,故此時(shí)只能和程序員一起定位。
?
?
Permanent Generation
溢出
通常由于
Perm
段裝載了大量的類而導(dǎo)致溢出,如
spring的動(dòng)態(tài)生成類。
目前的解決辦法:
1) 將
Perm
Size擴(kuò)大,一般256M能夠滿足要求
2) 若別無選擇,則只能將servlet的路徑加到CLASSPATH中,但一般不建議這么處理
C Heap溢出
系統(tǒng)對(duì)C Heap沒有限制,故C Heap發(fā)生問題時(shí),Java進(jìn)程所占內(nèi)存會(huì)持續(xù)增長(zhǎng),直到占用所有可用系統(tǒng)內(nèi)存
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

