首先我們來介紹一下JVM中的內(nèi)存區(qū)域
方法區(qū):在java的虛擬機(jī)中有一塊專門用來存放已經(jīng)加載的類信息掸掏、常量、靜態(tài)變量以 及方法代碼的內(nèi)存區(qū)域宙帝,叫做方法區(qū)丧凤。
常量池:常量池是方法區(qū)的一部分,主要用來存放常量和類中的符號引用等信息步脓。
堆區(qū):用于存放類的對象實(shí)例愿待。
棧區(qū):也叫java虛擬機(jī)棧,是由一個(gè)一個(gè)的棧幀組成的后進(jìn)先出的棧式結(jié)構(gòu)靴患,棧楨中存放方法運(yùn)行時(shí)產(chǎn)生的局部變量仍侥、方法出口等信息。當(dāng)調(diào)用一個(gè)方法時(shí)鸳君,虛擬機(jī)棧中就會創(chuàng)建一個(gè)棧幀存放這些數(shù)據(jù)农渊,當(dāng)方法調(diào)用完成時(shí),棧幀消失或颊,如果方法中調(diào)用了其他方法砸紊,則繼續(xù)在棧頂創(chuàng)建新的棧楨。
類的生命周期
類的加載
類的加載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中囱挑,將其放在運(yùn)行時(shí)數(shù)據(jù)區(qū)的方法區(qū)內(nèi)醉顽,然后在堆區(qū)創(chuàng)建一個(gè)java.lang.Class對象,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)平挑,最終產(chǎn)品是位于運(yùn)行時(shí)數(shù)據(jù)區(qū)的的堆區(qū)的CLASS文件游添,其封裝了方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)系草,并提供了java程序提供了訪問類在方法區(qū)內(nèi)的數(shù)據(jù)接口。
類的加載是由JAVA類加載器完成唆涝。
連接Linking
1驗(yàn)證:當(dāng)一個(gè)類被加載之后悄但,必須要驗(yàn)證一下這個(gè)類是否合法,比如這個(gè)類是不是符合字節(jié)碼的格式石抡、變量與方法是不是有重復(fù)、數(shù)據(jù)類型是不是有效助泽、繼承與實(shí)現(xiàn)是否合乎標(biāo)準(zhǔn)等等啰扛。總之嗡贺,這個(gè)階段的目的就是保證加載的類是能夠被jvm所運(yùn)行隐解。
2準(zhǔn)備:準(zhǔn)備階段的工作就是為類的靜態(tài)變量分配內(nèi)存并設(shè)為jvm默認(rèn)的初值,對于非靜態(tài)的變量诫睬,則不會為它們分配內(nèi)存煞茫。有一點(diǎn)需要注意,這時(shí)候摄凡,靜態(tài)變量的初值為jvm默認(rèn)的初值续徽,而不是我們在程序中設(shè)定的初值。jvm默認(rèn)的初值是這樣的:
?基本類型(int亲澡、long钦扭、short、char床绪、byte客情、boolean、float癞己、double)的默認(rèn)值為0膀斋。
?引用類型的默認(rèn)值為null。
?常量的默認(rèn)值為我們程序中設(shè)定的值痹雅,比如我們在程序中定義final static int a = 100仰担,則準(zhǔn)備階段中a的初值就是100。
3 解析:這一階段的任務(wù)就是把常量池中的符號引用轉(zhuǎn)換為直接引用练慕。
符號引用就是一組符號來描述目標(biāo)惰匙,可以是任何字面量
直接引用就是直接指向目標(biāo)的指針、相對偏移量或一個(gè)間接定位到目標(biāo)的句柄
類的初始化
在類的生命周期執(zhí)行完加載和連接之后就開始了類的初始化铃将。
在類的初始化階段项鬼,java虛擬機(jī)執(zhí)行類的初始化語句,為類的靜態(tài)變量賦值劲阎。
java類中對類變量指定初始值有兩種方式:
1绘盟、聲明類變量時(shí)指定初始值;2、使用靜態(tài)初始化塊為類變量指定初始值龄毡。
JVM初始化步驟
1吠卷、假如這個(gè)類還沒有被加載和連接,則程序先加載并連接該類
2沦零、假如該類的直接父類還沒有被初始化祭隔,則先初始化其直接父類
3、假如類中有初始化語句路操,則系統(tǒng)依次執(zhí)行這些初始化語句
類初始化時(shí)機(jī)
Java程序?qū)︻惖氖褂梅绞娇梢苑譃閮煞N:
1.主動使用
2.被動使用
只有當(dāng)對類的主動使用的時(shí)候才會導(dǎo)致類的初始化疾渴,類的主動使用包括以下六種:
除了以上六種情況,其他使用Java類的方式都被看作是對類的被動使用屯仗,都不會導(dǎo)致類的初始化搞坝。
1.父類靜態(tài)代碼塊;
2.子類靜態(tài)代碼塊魁袜;
3.父類非靜態(tài)代碼塊桩撮;
4.父類構(gòu)造函數(shù);
5.子類非靜態(tài)代碼塊峰弹;
6.子類構(gòu)造函數(shù)店量;
結(jié)束生命周期
在如下幾種情況下,Java虛擬機(jī)將結(jié)束生命周期
– 執(zhí)行了System.exit()方法
– 程序正常執(zhí)行結(jié)束
– 程序在執(zhí)行過程中遇到了異尘铣剩或錯(cuò)誤而異常終止
– 由于操作系統(tǒng)出現(xiàn)錯(cuò)誤而導(dǎo)致Java虛擬機(jī)進(jìn)程終止
JVM類加載機(jī)制
·全盤負(fù)責(zé)垫桂,當(dāng)一個(gè)類加載器負(fù)責(zé)加載某個(gè)Class時(shí),該Class所依賴的和引用的其他Class也將由該類加載器負(fù)責(zé)載入粟按,除非顯示使用另外一個(gè)類加載器來載入
·父類委托诬滩,先讓父類加載器試圖加載該類,只有在父類加載器無法加載該類時(shí)才嘗試從自己的類路徑中加載該類
·緩存機(jī)制灭将,緩存機(jī)制將會保證所有加載過的Class都會被緩存疼鸟,當(dāng)程序中需要使用某個(gè)Class時(shí),類加載器先從緩存區(qū)尋找該Class庙曙,只有緩存區(qū)不存在空镜,系統(tǒng)才會讀取該類對應(yīng)的二進(jìn)制數(shù)據(jù),并將其轉(zhuǎn)換成Class對象捌朴,存入緩存區(qū)吴攒。這就是為什么修改了Class后,必須重啟JVM砂蔽,程序的修改才會生效洼怔。
雙親委派模型的工作流程是:如果一個(gè)類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個(gè)類左驾,而是把請求委托給父加載器去完成镣隶,依次向上极谊,因此,所有的類加載請求最終都應(yīng)該被傳遞到頂層的啟動類加載器中安岂,只有當(dāng)父加載器在它的搜索范圍中沒有找到所需的類時(shí)轻猖,即無法完成該加載,子加載器才會嘗試自己去加載該類域那。
阿里的面試還是比較注重底層的實(shí)現(xiàn)原理的咙边,看來阿里不是隨便就能進(jìn)去的。怎么樣你覺得你合格嗎次员?喜歡的朋友可以關(guān)注我哦样眠。
學(xué)習(xí)Java的同學(xué)注意了!4渲狻!學(xué)習(xí)過程中遇到什么問題或者想獲取學(xué)習(xí)資源的話辫秧,歡迎加入Java學(xué)習(xí)交流群346942462束倍,我們一起學(xué)Java!