這些日子一直在研究jvm內存管理的東西,網上的知識很多,總結一下,以備後用。
首先,剛學java的時候就知道java類文件是以 .java爲後綴的文件,經過javac命令編譯後,編譯成class文件,class文件中都是二進制格式的數據,所以想要看編譯後的內容是什麼,可以採用jdk自帶的javap命令查看。
記得剛學java的時候覺得java虛擬機厲害的很,java的風光正是建立在它的功勞之上。JVM (java vitual machine)。JVM中有個組成部分爲類加載器(ClassLoader),負責java文件編譯後class文件的加載,加載到哪呢,加載到內存。那下面來說一下JVM的內存管理。
JVM的內存分棧內存、堆內存、本地方法棧和方法區四部分。java通過類加載器來加載class文件,加載到內存後,會把類、方法、常變量放到堆內存中。因爲java是自動進行垃圾回收的,所以放入堆內存中的東西,哪些該回收,哪些不該回收?這都需要jvm去額外的線程去進行判斷。但如果對於一個大型的J2EE系統來說,當創建的對象及方法變量比較多時,即堆內存中的對象比較多,如果一個一個對象去進行循環判斷是否該回收時,這樣的回收機制未免太耗時了,系統的性能一定會下降,jvm爲了提高jvm執行效率,採用了堆內存分區管理的機制。
JVM把堆內存分三大塊:Young Generation Space 新生區(也稱新生代)、Tenure generation space養老區(也稱舊生代)、Permanent Space 永久存儲區。分區是爲了進行模塊化管理,管理不同的對象及變量以提高JVM的執行效率。
對於Young Generation Space ,它主要用來存儲新創建的對象,內存大小會比較小,垃圾回收會比較頻繁。對此區又分三個區域:一個Eden Space和兩個Survivor Space。有一個前輩對這三個區域描述的相當透徹:
- 當對象在堆創建時,將進入年輕代的Eden Space。
- 垃圾回收器進行垃圾回收時,掃描Eden Space和A Suvivor Space,如果對象仍然存活,則複製到B Suvivor Space,如果B Suvivor Space已經滿,則複製 Old Gen
- 掃描A Suvivor Space時,如果對象已經經過了幾次的掃描仍然存活,JVM認爲其爲一個Old對象,則將其移到Old Gen。
- 掃描完畢後,JVM將Eden Space和A Suvivor Space清空,然後交換A和B的角色(即下次垃圾回收時會掃描Eden Space和BSuvivor Space。
對於Tenure generation space,它主要是用來存儲那些長時間被引用的對象。因爲它裏面存放的是經過幾次在Young Genderation Space 進行掃描判斷過仍存活的對象,內存大小會比較大,垃圾回收頻率會比較小。
對於Permanent Space 永久存儲區,它是用來存儲一些值信息不經常變更的東東,有類定義、字節碼和常量等。
內存管理表:
1、分代GC策略
組成 |
詳解 |
堆(Heap)內存
|
JVM採用一種分代回收(generational collection)的策略,用較高的頻率對年輕的對象(young generation)進行掃描和回收,這種叫做minor collection,而對老對象(old generation)的檢查回收頻率要低很多,稱爲major collection。這樣就不需要每次GC都將內存中所有對象都檢查一遍,以便讓出更多的系統資源供應用系統使用。 |
非堆內存
|
GC不會在主程序運行期對PermGen Space進行清理,所以如果你的應用中有很多CLASS的話,就很可能出現PermGen Space錯誤。 |
2、 內存分配(申請)過程
步驟 |
操作 |
1 |
JVM會試圖爲相關Java對象在Eden中初始化一塊內存區域; |
2 |
當Eden空間足夠時,內存申請結束。否則到下一步; |
3 |
JVM試圖釋放對Eden中所有不活躍的對象minor collection,釋放後若Eden空間仍然不足以放入新對象,則試圖將部分Eden中活躍對象放入Survivor區; |
4 |
Survivor區被用來作爲Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,否則會被保留在Survivor區; |
5 |
當OLD區空間不夠時,JVM會在OLD區進行major collection; |
6 |
完全垃圾收集後,若Survivor及OLD區仍然無法存放從Eden複製過來的部分對象,導致JVM無法在Eden區爲新對象創建內存區域,則出現"Out of memory錯誤" |
3、對象衰老過程
步驟 |
操作 |
1 |
young generation的內存,由一塊Eden和兩塊Survivor Space構成。新創建對象的內存都分配自eden。兩塊Survivor Space總有會一塊是空閒的,用作copying collection的目標空間。Minor collection的過程就是將eden和在用survivor space中的活對象copy到空閒survivor space中。對象在young generation裏經歷了一定次數的minor collection後,年紀大了,就會被移到old generation中,稱爲tenuring。 |
2 |
剩餘內存空間不足會觸發GC,如eden空間不夠了就要進行minor collection,old generation空間不夠要進行major collection,permanent generation空間不足會引發Full GC。 |
GC觸發條件
GC類型 | 觸發條件 | 觸發時發生了什麼 | 注意 | 查看方式 |
YGC | eden空間不足 |
清空Eden+from survivor中所有no ref的對象佔用的內存 重新調整Eden 和from的大小(parallel GC會觸發此項) |
全過程暫停應用 是否爲多線程處理由具體的GC決定 |
jstat –gcutil gc log |
FGC |
old空間不足 |
清空heap中no ref的對象 permgen中已經被卸載的classloader中加載的class信息 如配置了CollectGenOFirst,則先觸發YGC(針對serial GC) 如配置了ScavengeBeforeFullGC,則先觸發YGC(針對serial GC) |
全過程暫停應用 是否爲多線程處理由具體的GC決定 是否壓縮需要看配置的具體GC |
jstat –gcutil gc log |