除直接調(diào)用
System.gc
外,觸發(fā)
Full GC
執(zhí)行的情況有如下四種。
1.
舊生代空間不足
舊生代空間只有
在新生代對(duì)象轉(zhuǎn)入及創(chuàng)建為大對(duì)象、大數(shù)組時(shí)才會(huì)出現(xiàn)不足的現(xiàn)象,當(dāng)執(zhí)行
Full GC
后空間仍然不
足,則拋出如下錯(cuò)誤:
java.lang.OutOfMemoryError: Java heap space
為避免以上兩種狀況引起
的
FullGC
,調(diào)優(yōu)時(shí)應(yīng)盡量做到讓對(duì)象在
Minor GC
階段被回收、讓對(duì)象在新生代多存活一段時(shí)間及不
要?jiǎng)?chuàng)建過大的對(duì)象及數(shù)組。
2. Permanet Generation
空間滿
PermanetGeneration
中存放的為一些
class
的信息等,當(dāng)系統(tǒng)中
要加載的類、反射的類和調(diào)用的方法較多時(shí),
Permanet Generation
可能會(huì)被占滿,在未配置為采
用
CMS GC
的情況下會(huì)執(zhí)行
Full GC
。如果經(jīng)過
Full GC
仍然回收不了,那么
JVM
會(huì)拋出如下錯(cuò)誤信
息:
java.lang.OutOfMemoryError: PermGen space
為避免
Perm Gen
占滿造成
Full GC
現(xiàn)象,可
采用的方法為增大
Perm Gen
空間或轉(zhuǎn)為使用
CMS GC
。
3. CMS GC
時(shí)出現(xiàn)
promotion failed
和
concurrent mode failure
對(duì)于采用
CMS
進(jìn)行舊生代
GC
的
程序而言,尤其要注意
GC
日志中是否有
promotion failed
和
concurrent mode failure
兩種狀況,當(dāng)
這兩種狀況出現(xiàn)時(shí)可能會(huì)觸發(fā)
Full GC
。
promotionfailed
是在進(jìn)行
Minor GC
時(shí),
survivor space
放
不下、對(duì)象只能放入舊生代,而此時(shí)舊生代也放不下造成的;
concurrent mode failure
是在執(zhí)行
CMS GC
的過程中同時(shí)有對(duì)象要放入舊生代,而此時(shí)舊生代空間不足造成的。 應(yīng)對(duì)措施為:增大
survivorspace
、舊生代空間或調(diào)低觸發(fā)并發(fā)
GC
的比率,但在
JDK 5.0+
、
6.0+
的版本中有可能會(huì)由
于
JDK
的
bug29
導(dǎo)致
CMS
在
remark
完畢后很久才觸發(fā)
sweeping
動(dòng)作。對(duì)于這種狀況,可通過設(shè)置
-
XX:CMSMaxAbortablePrecleanTime=5
(單位為
ms
)來避免。
4.
統(tǒng)計(jì)得到的
Minor GC
晉升到舊生代的平均大小大于舊生代的剩余空間
這是一個(gè)較為復(fù)雜的觸發(fā)
情況,
Hotspot
為了避免由于新生代對(duì)象晉升到舊生代導(dǎo)致舊生代空間不足的現(xiàn)象,在進(jìn)行
Minor
GC
時(shí),做了一個(gè)判斷,如果之前統(tǒng)計(jì)所得到的
Minor GC
晉升到舊生代的平均大小大于舊生代的剩
余空間,那么就直接觸發(fā)
Full GC
。 例如程序第一次觸發(fā)
MinorGC
后,有
6MB
的對(duì)象晉升到舊生
代,那么當(dāng)下一次
Minor GC
發(fā)生時(shí),首先檢查舊生代的剩余空間是否大于
6MB
,如果小于
6MB
,
則執(zhí)行
Full GC
。 當(dāng)新生代采用
PSGC
時(shí),方式稍有不同,
PS GC
是在
Minor GC
后也會(huì)檢查,例如上
面的例子中第一次
Minor GC
后,
PS GC
會(huì)檢查此時(shí)舊生代的剩余空間是否大于
6MB
,如小于,則觸
發(fā)對(duì)舊生代的回收。 除了以上
4
種狀況外,對(duì)于使用
RMI
來進(jìn)行
RPC
或管理的
Sun JDK
應(yīng)用而言,默
認(rèn)情況下會(huì)一小時(shí)執(zhí)行一次
Full GC
。可通過在啟動(dòng)時(shí)通過
- java
Dsun.rmi.dgc.client.gcInterval=3600000
來設(shè)置
Full GC
執(zhí)行的間隔時(shí)間或通過
-XX:+
DisableExplicitGC
來禁止
RMI
調(diào)用
System.gc
。
描述一下
JVM
加載
class
文件的原理機(jī)制?
JVM
中類的裝載是由類加載器(
ClassLoader
)和它的子類來實(shí)現(xiàn)的,
Java
中的類加載器是一個(gè)重要
的
Java
運(yùn)行時(shí)系統(tǒng)組件,它負(fù)責(zé)在運(yùn)行時(shí)查找和裝入類文件中的類。 由于
Java
的跨平臺(tái)性,經(jīng)過編
譯的
Java
源程序并不是一個(gè)可執(zhí)行程序,而是一個(gè)或多個(gè)類文件。當(dāng)
Java
程序需要使用某個(gè)類時(shí),
JVM
會(huì)確保這個(gè)類已經(jīng)被加載、連接(驗(yàn)證、準(zhǔn)備和解析)和初始化。類的加載是指把類的
.class
文
件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個(gè)字節(jié)數(shù)組讀入
.class
文件,然后產(chǎn)生與所加載類對(duì)應(yīng)的
Class
對(duì)象。加載完成后,
Class
對(duì)象還不完整,所以此時(shí)的類還不可用。當(dāng)類被加載后就進(jìn)入連接
階段,這一階段包括驗(yàn)證、準(zhǔn)備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認(rèn)的初始值)和解析(將符號(hào)引用
替換為直接引用)三個(gè)步驟。最后
JVM
對(duì)類進(jìn)行初始化,包括:
1)
如果類存在直接的父類并且這個(gè)
類還沒有被初始化,那么就先初始化父類;
2)
如果類中存在初始化語句,就依次執(zhí)行這些初始化語
句。 類的加載是由類加載器完成的,類加載器包括:根加載器(
BootStrap
)、擴(kuò)展加載器
(
Extension
)、系統(tǒng)加載器(
System
)和用戶自定義類加載器(
java.lang.ClassLoader
的子
類)。從
Java 2
(
JDK 1.2
)開始,類加載過程采取了父親委托機(jī)制(
PDM
)。
PDM
更好的保證了
Java
平臺(tái)的安全性,在該機(jī)制中,
JVM
自帶的
Bootstrap
是根加載器,其他的加載器都有且僅有一個(gè)
父類加載器。類的加載首先請(qǐng)求父類加載器加載,父類加載器無能為力時(shí)才由其子類加載器自行加
載。
JVM
不會(huì)向
Java
程序提供對(duì)
Bootstrap
的引用。下面是關(guān)于幾個(gè)類加載器的說明:
Bootstrap
:一般用本地代碼實(shí)現(xiàn),負(fù)責(zé)加載
JVM
基礎(chǔ)核心類庫(
rt.jar
);
Extension
:從
java.ext.dirs
系統(tǒng)屬性所指定的目錄中加載類庫,它的父加載器是
Bootstrap
;
System
:又叫應(yīng)用類加載器,其父類是
Extension
。它是應(yīng)用最廣泛的類加載器。它從環(huán)境變
量
classpath
或者系統(tǒng)屬性
java.class.path
所指定的目錄中記載類,是用戶自定義加載器的默認(rèn)
父加載器。
到了這里,關(guān)于什么時(shí)候會(huì)觸發(fā)FullGC?描述一下JVM加載class文件的原理機(jī)制?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!