重慶付費(fèi)網(wǎng)站推廣友情鏈接交換工具
目錄
1.JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)
2.JVM類(lèi)加載過(guò)程
3.雙清委派模型
4.垃圾回收機(jī)制(GC)
找出誰(shuí)是垃圾方案一:引用計(jì)數(shù)
找出誰(shuí)是垃圾:方案二,可達(dá)性分析
釋放垃圾的內(nèi)存空間
判斷垃圾:jvm依據(jù)對(duì)象的年齡對(duì) 對(duì)象進(jìn)行區(qū)域劃分。
回收垃圾方式:分代回收
1.JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)
JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)域 也叫做:JVM內(nèi)存布局。
JVM內(nèi)存布局 和 java內(nèi)存模型完全不同,JVM內(nèi)存布局由5大部分組成。
1.堆區(qū)(線程共享):程序中所有創(chuàng)建的對(duì)象都保存在堆中。JVM最大空間。
2.棧(線程私有):
????????1>.java虛擬機(jī)棧作用(線程私有):Java虛擬機(jī)棧的生命周期 和 線程相同,Java虛擬機(jī)棧描述了java方法執(zhí)行的內(nèi)存模型:每個(gè)方法在執(zhí)行時(shí) 都會(huì)創(chuàng)建一個(gè)棧幀,用來(lái)儲(chǔ)存局部變量,方法之間的調(diào)用關(guān)系,動(dòng)態(tài)鏈接,方法出口等等。
? ? ? ? 2>.本地方法棧:與虛擬機(jī)棧類(lèi)似,只不過(guò)是給本地方法使用的,本地方法由C++代碼編寫(xiě)。
3.程序計(jì)數(shù)器(線程私有):保存下一條要執(zhí)行的指令的地址。這里不是CPU寄存器儲(chǔ)存的,而是內(nèi)存空間,指令是java的字節(jié)碼。不是二進(jìn)制機(jī)器語(yǔ)言。
4.元數(shù)據(jù)區(qū):(以前叫方法區(qū))保存java代碼中涉及類(lèi)的相關(guān)信息。類(lèi)的static屬性。
在一個(gè)java進(jìn)程中,元數(shù)據(jù)區(qū) 和 堆 是只有一份的。即同一個(gè)進(jìn)程中的所有線程共用一份數(shù)據(jù)。
一個(gè)java進(jìn)程中有多個(gè)線程,多個(gè)線程都有自己的 程序計(jì)數(shù)器 和 棧。所以每個(gè)線程都需要保存自己的“程序計(jì)數(shù)器” 每個(gè)線程都需要記錄自己的 調(diào)用關(guān)系。
檢測(cè)一下是掌握的怎么樣,下面代碼中的變量都儲(chǔ)存在哪些區(qū)域?
public class test4 {static class Test{private int a;private Test b = new Test();private static int c;private static Test d = new Test();}public static void main(String[] args) {int e = 10;Test f = new Test();}
}
一般地:
局部變量:棧
成員變量:堆
靜態(tài)成員變量:元數(shù)據(jù)區(qū)(方法區(qū))
2.JVM類(lèi)加載過(guò)程
一個(gè)類(lèi)的生命周期大致為下幾個(gè)過(guò)程。
編寫(xiě)一個(gè)java程序 會(huì)得到一個(gè) .java文件,在經(jīng)過(guò)javac 編譯 就會(huì)得到一個(gè) .class文件。
想要運(yùn)行java 進(jìn)程,jvm就需要 讀取 .class 文件并執(zhí)行里面的指令。
jvm讀取到 .class里面的內(nèi)容 這個(gè)就是類(lèi)加載。把類(lèi) 涉及的字節(jié)碼,從硬盤(pán)讀取到 內(nèi)存里。
?加載一個(gè) .claas文件,就會(huì)對(duì)應(yīng)創(chuàng)建一個(gè)類(lèi)對(duì)象。類(lèi)對(duì)象包含了.class
文件里的各種信息。
類(lèi)名字,類(lèi)的屬性,類(lèi)有哪些方法,繼承的父類(lèi)有哪些,實(shí)現(xiàn)的接口有哪些....
具體步驟:
1.加載:把 .class 文件找到,然后打開(kāi)并讀取文件的內(nèi)容。
代碼中先見(jiàn)到 類(lèi)的名字,然后進(jìn)一步找到對(duì)應(yīng)的 .class 文件(涉及一系列的目錄查找過(guò)程)
2.驗(yàn)證:驗(yàn)證讀到的 .class 文件的數(shù)據(jù)是否正確,是否合法。
java標(biāo)準(zhǔn)文檔中明確規(guī)定 .class 文件的格式是怎么樣的。
3.準(zhǔn)備:分配內(nèi)存空間。
根據(jù)讀取到的內(nèi)容大小,確定出類(lèi)對(duì)象需要的內(nèi)存空間,申請(qǐng)這樣大小的空間,并把這個(gè)空間全部初始化為0.
4.解析:主要針對(duì)類(lèi)中的字符串常量進(jìn)行處理
java虛擬機(jī) 將字符串常量池中的 符號(hào)引用 替換為直接引用的過(guò)程,也就是初始化常量。
符號(hào)引用 其實(shí)就是指(字符串常量已經(jīng)在 .class文件中)文件中 符號(hào)的位置,就是偏移量。
直接引用 就是直接保存變量的地址。
5.初始化:針對(duì) 類(lèi)對(duì)象 做最終的初始化操作,執(zhí)行靜態(tài)成員賦值語(yǔ)句。
3.雙清委派模型
操作: 輸入一個(gè) 類(lèi)的全限定名(類(lèi)似于java.lang.String),的到對(duì)應(yīng)的 .class 文件。
屬于 jvm加載類(lèi)中的第一個(gè)機(jī)制:加載
Bootstrap ClassLoader(加載 標(biāo)準(zhǔn)庫(kù)中的類(lèi))
ExtensionClassLoader(加載 擴(kuò)展庫(kù)的類(lèi))
ApplicationClassLoader(負(fù)責(zé)加載第三方庫(kù)的類(lèi))
?
為什么會(huì)是這個(gè)流程?
核心目的是 方式用戶自己寫(xiě)的類(lèi)把?標(biāo)準(zhǔn)庫(kù) 或者 擴(kuò)展庫(kù)給覆蓋掉。
保證 標(biāo)準(zhǔn)庫(kù)的類(lèi)是第一位,擴(kuò)展庫(kù)的類(lèi)的是第二位。最后是第三方庫(kù)的類(lèi)。
防止程序員 不小心創(chuàng)建一個(gè) 和 系統(tǒng)中已有的類(lèi)重名的類(lèi)。導(dǎo)致加載的時(shí)候覆蓋掉了系統(tǒng)的類(lèi)。
4.垃圾回收機(jī)制(GC)
GC 主要存在哪里呢?
棧 和 程序計(jì)數(shù)器 主要都是跟隨線程的結(jié)束而結(jié)束。
元數(shù)據(jù)區(qū):類(lèi)對(duì)象涉及到的類(lèi)加載,一個(gè)程序里面嗎要加載得類(lèi)都是有上限的,不會(huì)出現(xiàn)無(wú)限增長(zhǎng)的情況。
所以 堆是GC得主要戰(zhàn)區(qū)。
垃圾回收,回收內(nèi)存 都是一對(duì)象為維度進(jìn)行回收的。
GC回收的流程:1.找出誰(shuí)是垃圾???????? 2.釋放垃圾的內(nèi)存空間
找出誰(shuí)是垃圾方案一:引用計(jì)數(shù)
給每個(gè)對(duì)象分配一個(gè)計(jì)數(shù)器,衡量有多少個(gè)引用指向。
每增加一個(gè)引用,計(jì)數(shù)器+1
每減少一個(gè)引用,計(jì)數(shù)器-1,如果計(jì)數(shù)器為0,此對(duì)象就垃圾了需要回收。
此時(shí) 對(duì)象中的計(jì)數(shù)器為0,就視為垃圾,需要回收。
上述方案存在兩個(gè)問(wèn)題:
1.消耗額外空間去 儲(chǔ)存計(jì)數(shù)器
假設(shè)Tets類(lèi),只有一個(gè)int(4字節(jié))成員,那么就要花2個(gè)字節(jié)儲(chǔ)存計(jì)數(shù)器,內(nèi)存多用了 50%
2.引用計(jì)數(shù)可能會(huì)導(dǎo)致“循環(huán)引用”,使得上述判定出錯(cuò)。
這種情況就是最后 這倆對(duì)象計(jì)數(shù)器都不是0,都不能被釋放。
找出誰(shuí)是垃圾:方案二,可達(dá)性分析
用時(shí)間換取空間。
JVM中專門(mén)搞了一波周期性的線程,掃面代碼中的所有對(duì)象,判定某個(gè)對(duì)象是否“可達(dá)”。
對(duì)應(yīng)的,不可達(dá)的就是垃圾。
JVM中有所有對(duì)象的總名單,按照名單點(diǎn)名,如果沒(méi)有到的 ,就是垃圾。
JVM中有很多的root根,從這個(gè)root開(kāi)始可以把所有的對(duì)象都遍歷到。遍歷不到但是名單上存在就是垃圾。
釋放垃圾的內(nèi)存空間
1.標(biāo)記-清除法
如果直接對(duì)內(nèi)存空間進(jìn)行標(biāo)記清楚,就有可能導(dǎo)致碎片化的空間無(wú)法充分利用。
這樣剩下的三個(gè)空間就不容易利用了,碎片化的空間不能進(jìn)行申請(qǐng)連續(xù)的空間。
2.復(fù)制算法
將被回收后的空間的一分為二,把不是垃圾的對(duì)象拷貝到另一側(cè)。確保回收后得到連續(xù)的空間
這個(gè)算法缺點(diǎn)很明顯:
1.內(nèi)存空間利用率低
2.如果存活下來(lái)的對(duì)象比較多,復(fù)制成本也很大。
3.標(biāo)記-整理
與標(biāo)記-清楚類(lèi)似,但是不一樣的是后續(xù)并不是直接回收對(duì)象,而是讓所有的存活對(duì)象都向前移動(dòng),最后直接清理掉邊界標(biāo)記的就可以了。
4.jvm中真正的解決方案。
判斷垃圾:jvm依據(jù)對(duì)象的年齡對(duì) 對(duì)象進(jìn)行區(qū)域劃分。
如果獲得年齡,使用可達(dá)性分析 對(duì)對(duì)象進(jìn)行掃描,每次描掃后對(duì)象的年齡就+1
1.伊甸區(qū)比較大,讓新創(chuàng)建的對(duì)象存放,大多數(shù)新創(chuàng)建的對(duì)象都活不過(guò)第一輪GC,留下來(lái)的對(duì)象拷貝到幸存區(qū)。
2.幸存區(qū),是兩個(gè)相按照復(fù)制算法將存活久對(duì)象復(fù)制到幸存區(qū),反復(fù)多次。幸存區(qū)里也會(huì)為了保留完整空間進(jìn)行左右多次復(fù)制。
3.一個(gè)對(duì)象在幸存區(qū)多次被拷貝,年齡不斷增長(zhǎng),就要拷貝到老年代了。
4.根據(jù)經(jīng)驗(yàn)規(guī)律,老年代的對(duì)象生命周期都比較長(zhǎng),即便如此也是要進(jìn)行可達(dá)性分析的。
但是老年代的GC頻率較低。老年代也需要通過(guò)標(biāo)記整理。
回收垃圾方式:分代回收
分代回收時(shí)JVM的GC基本思想方法。
jvm還提供許多“垃圾回收器”對(duì)上述的分代回收 作進(jìn)一步的擴(kuò)充和具體實(shí)現(xiàn)。
CMS涉及理念,把整個(gè)GC過(guò)程拆分成多個(gè)階段,能和業(yè)務(wù)線程并發(fā)運(yùn)行的。就盡量并發(fā)減少STW時(shí)間。
G1把整個(gè)內(nèi)存分成很多快,不同的顏色表示這個(gè)一塊區(qū)域是哪一塊(新生代,老年代,幸存區(qū)...)
進(jìn)行GC時(shí)不要求一周期就把多個(gè)內(nèi)存都回收,只要回收一部分就好。限制一輪GC的工作量,目的是使STW控制在一定范圍,降低STW的影響。