1、為什么需要虛擬機(jī)
http://baijiahao.baidu.com/s?id=1594810966058734748&wfr=spider&for=pc
2、虛擬機(jī)體系架構(gòu)
https://blog.csdn.net/u013256816/article/details/51484031
https://blog.csdn.net/zhangjg_blog/article/details/20380971
3、虛擬機(jī)內(nèi)存區(qū)域
- 程序計(jì)數(shù)器:當(dāng)前線程執(zhí)行的字節(jié)碼的行號(hào)指示器。
- 棧:棧是線程私有的,每創(chuàng)建一個(gè)線程,虛擬機(jī)就會(huì)為這個(gè)線程創(chuàng)建一個(gè)虛擬機(jī)棧,虛擬機(jī)棧表示Java方法執(zhí)行的內(nèi)存模型,每調(diào)用一個(gè)方法就會(huì)為每個(gè)方法生成一個(gè)棧幀(Stack Frame),用來(lái)存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。每個(gè)方法被調(diào)用和完成的過(guò)程,都對(duì)應(yīng)一個(gè)棧幀從虛擬機(jī)棧上入棧和出棧的過(guò)程。虛擬機(jī)棧的生命周期和線程是相同的”。
本地棧: - 堆:存放對(duì)象
- 方法區(qū):存放類信息(class文件種的常量池)、靜態(tài)變量(static修飾)、常量(final修飾)
4、垃圾回收機(jī)制
垃圾回收一般必須完成兩件事:檢測(cè)出垃圾;回收垃圾。
- 檢測(cè)垃圾的算法:
(1):引用計(jì)數(shù)法:給對(duì)象增加添加一個(gè)引用計(jì)數(shù)器,有一個(gè)地方引用,計(jì)數(shù)值就加1;引用失效則減1;計(jì)數(shù)器為0說(shuō)明可以垃圾回收。
缺點(diǎn):無(wú)法解決相互引用的問(wèn)題
(2) : 可達(dá)性分析算法:
以一系列"GC Roots"對(duì)象為起點(diǎn),判斷別的對(duì)象與他們是否存在引用鏈關(guān)系;沒(méi)有則說(shuō)明該對(duì)象可被回收。
可作為GC Roots的對(duì)象:
(1):虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
(2):方法區(qū)中類靜態(tài)屬性引用的對(duì)象
(3):方法區(qū)中常量引用的對(duì)象
(4):本地方法棧(native方法)引用的對(duì)象 - 垃圾回收算法
(1):標(biāo)記——清除算法
缺點(diǎn):標(biāo)記清除產(chǎn)生大量不連續(xù)的碎片空間,導(dǎo)致分配大對(duì)象無(wú)法找到足夠的內(nèi)存提前觸發(fā)垃圾回收。
(2):復(fù)制算法
年輕代垃圾回收采用這種算法,把年輕代分為一個(gè)Eden區(qū),2個(gè)Survivor區(qū)(from和to)。
大小比例是:Eden:from:to = 8 :1:1。
對(duì)象在Eden和from中出生,垃圾回收后還存在放在to中,to不足則需要老年代擔(dān)保。
缺點(diǎn):對(duì)象存活率高時(shí),復(fù)制效率變低;需要?jiǎng)e的空間進(jìn)行擔(dān)保,以應(yīng)對(duì)所有對(duì)象存活的極端情況。
(3):標(biāo)記——整理算法
標(biāo)記后存活對(duì)象移向一端,老年代采用的GC算法。
(4):分代收集算法
為什么新生代內(nèi)存需要有兩個(gè)Survivor區(qū) - java中的垃圾回收器:
現(xiàn)在java虛擬機(jī)垃圾回收采用的分代收集算法,因此年輕代和老年代有各自的垃圾回收器。
Serial收集器:年輕代的單線程收集器,垃圾回收時(shí)必須暫停所有的工作線程。
ParNew收集器:Serial收集器的多線程版。
Serial適合運(yùn)行在單CPU,ParNew適合運(yùn)行在多CPU下,目前這有這2個(gè)收集器適合與CMS收集器配合。
CMS收集器:Concurrent Mark Sweep,由名字可以看出基于“標(biāo)記——清除”算法實(shí)現(xiàn),是一種以獲取最少停頓時(shí)間為目標(biāo)的收集器。
CMS如何減少時(shí)間停頓? - CMS垃圾回收分為4個(gè)過(guò)程:
1初始標(biāo)記:只標(biāo)記老年代GC roots“根對(duì)象” 和年輕代中對(duì)老年代的可達(dá)對(duì)象,速度很快,會(huì)停止其他線程
2并發(fā)標(biāo)記:根據(jù)初始標(biāo)記得到的存活對(duì)象,遞歸其引用鏈,標(biāo)記其他可達(dá)對(duì)象。因?yàn)樵撾A段是并發(fā)的,標(biāo)記過(guò)程中工作線程也在運(yùn)行,就有可能出現(xiàn)新生代對(duì)象晉升到老年代或者直接在老年代中中分配對(duì)象。為了提高重新標(biāo)記的效率,該階段會(huì)把上述對(duì)象所在的Card標(biāo)識(shí)為Dirty,后續(xù)只需掃描這些Dirty Card的對(duì)象,避免掃描整個(gè)老年代。
3重新標(biāo)記:重新對(duì)GC roots 、Dirty Card等對(duì)象進(jìn)行標(biāo)記,該過(guò)程會(huì)暫停工作線程
4并發(fā)整理:清理垃圾
CMS的優(yōu)缺點(diǎn): - 優(yōu)點(diǎn):并發(fā)收集,減少停頓
- 缺點(diǎn):
1基于標(biāo)記——清除算法,會(huì)產(chǎn)生大量的空間碎片。還好CMS可以設(shè)置參數(shù)對(duì)內(nèi)存碎片進(jìn)行合并整理。
2CMS在并發(fā)整理階段客戶線程還在運(yùn)行,于是得預(yù)留空間給客戶線程使用,當(dāng)老年代空間達(dá)到92%就會(huì)觸發(fā)一次Full gc。
總的來(lái)說(shuō):CMS回收器減少了回收的停頓時(shí)間,但是降低了堆空間的利用率。
http://www.itdecent.cn/p/2a1b2f17d3e4
https://blog.csdn.net/wfh6732/article/details/57490195?utm_source=itdadao&utm_medium=referral
5、 內(nèi)存分配機(jī)制
1、大多數(shù)情況下,對(duì)象在新生代Eden區(qū)分配,Eden區(qū)空間不足時(shí)觸發(fā)minor GC.
2、大對(duì)象直接在老年代分配空間。典型的大對(duì)象是很長(zhǎng)的字符串和數(shù)組,虛擬機(jī)中有一個(gè)參數(shù),空間大于這個(gè)參數(shù)的對(duì)象直接在老年代分配。
3、在Eden出生的對(duì)象經(jīng)過(guò)一次minor GC后仍然存在,且能被survivor分區(qū)容納,年齡就加1,當(dāng)年齡增加到15(值可以設(shè)置)就會(huì)晉升到老年代。
4、動(dòng)態(tài)年齡判斷:不是必須達(dá)到某個(gè)年齡才能晉升到老年代,相同年齡所有對(duì)象總和大于survivor50%,可以直接進(jìn)入老年代。
5、空間擔(dān)保分配:進(jìn)行Minor GC之前,需要檢查老年代最大連續(xù)空間是否大于所有新生對(duì)象總和,如果小于,看看虛擬機(jī)是否允許擔(dān)保失敗,允許的話繼續(xù)檢查老年代最大的連續(xù)可用空間是否大于歷次晉升到老年區(qū)的平均值,大于的話可以進(jìn)行Minor GC,小于的話或者不允許是擔(dān)保失敗則要進(jìn)行一次Full GC。
6、類加載過(guò)程
- 類加載過(guò)程:加載——驗(yàn)證——準(zhǔn)備——解析——初始化
1、加載
通過(guò)一個(gè)類的全限定名來(lái)獲取該類的二進(jìn)制字節(jié)流,對(duì)數(shù)據(jù)轉(zhuǎn)換后存儲(chǔ)在方法區(qū),在方法區(qū)生成一個(gè)代表該類的class對(duì)象,作為數(shù)據(jù)的訪問(wèn)入口。
需要注意的是:二進(jìn)制字節(jié)流不一定要從class中獲取,可以從jar包、網(wǎng)絡(luò)、或者動(dòng)態(tài)代理生成的代理類。
2、驗(yàn)證:確保Class文件的字節(jié)流符合虛擬機(jī)的要求
- 文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范,例如是否以魔數(shù)開頭,主次版本號(hào)是否在當(dāng)前虛擬機(jī)的處理范圍內(nèi),常量池的常量是否符合要求等,通過(guò)這個(gè)階段驗(yàn)證后字節(jié)流才會(huì)進(jìn)入方法區(qū)中存儲(chǔ)。
- 元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,保證符合Java語(yǔ)言規(guī)范,例如:驗(yàn)證該類是否繼承了不被允許繼承的類(final),是否實(shí)現(xiàn)了接口的所有方法等。
- 字節(jié)碼驗(yàn)證:對(duì)類的方法體進(jìn)行校驗(yàn)分析,例如:方法中的類型轉(zhuǎn)換是否有效等
- 符號(hào)引用驗(yàn)證: 對(duì)類自身以外的信息進(jìn)行驗(yàn)證,例如:是否能夠通過(guò)全限定名找到對(duì)應(yīng)的類等
3、準(zhǔn)備:為類變量(不包括實(shí)例變量)在方法區(qū)分配內(nèi)存,并設(shè)置初始值。
4、解析:將常量池內(nèi)的符號(hào)引用替換為直接引用。
5、初始化:執(zhí)行靜態(tài)代碼塊,為靜態(tài)變量賦值,該過(guò)程是線程安全的,事餓漢式單例的基礎(chǔ)。
7、類加載器
java有四種類加載器,啟動(dòng)類加載器(Bootstap ClassLoader),擴(kuò)展類加載器(Extension ClassLoader),應(yīng)用程序類加載器(Application ClassLoader),也稱為系統(tǒng)加載器,應(yīng)用程序一般是由這3種類加載器相互配合加載,每種加載器會(huì)加載特定路徑下的源碼。
雙親委派模型的工作過(guò)程:一個(gè)類加載器收到類加載的請(qǐng)求,他首先不會(huì)自己區(qū)加載,而是把委托其父類加載器去加載,最終都會(huì)讓啟動(dòng)類加載器去嘗試加載,只有當(dāng)父加載器無(wú)法完成這個(gè)加載請(qǐng)求(在他的搜索范圍沒(méi)有找到這個(gè)類),子加載器才會(huì)嘗試自己去加載。
雙親委派模型的好處:避免加載到跟系統(tǒng)中定義的同名的類,造成系統(tǒng)的混亂。
8 四種引用
- 強(qiáng)引用
賦值符號(hào)即為強(qiáng)引用,例如: Object o1 = new Object();
或者o1 = o2,當(dāng)內(nèi)存空間不足時(shí),虛擬機(jī)即使拋出內(nèi)存溢出停止程序也不會(huì)回收強(qiáng)引用對(duì)象,因此在使用過(guò)程中,如果是全局變量,不用的時(shí)候可以置為null,下次垃圾回收內(nèi)存就會(huì)被回收。 - 軟引用
內(nèi)存空間足夠時(shí),垃圾回收時(shí)不會(huì)回收;內(nèi)存空間不足時(shí),垃圾回收時(shí)會(huì)回收軟引用的內(nèi)存。主要用于避免內(nèi)存溢出。 - 弱引用
垃圾回收時(shí)不管內(nèi)存空間是否足夠均會(huì)回收。主要用于避免內(nèi)存泄漏。(Handler內(nèi)存溢出的解決方式) - 虛引用