目錄
創(chuàng)新互聯(lián)咨詢熱線:18980820575,為您提供成都網(wǎng)站建設(shè)網(wǎng)頁(yè)設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),創(chuàng)新互聯(lián)網(wǎng)頁(yè)制作領(lǐng)域10余年,包括成都活動(dòng)板房等多個(gè)方面擁有多年的網(wǎng)站制作經(jīng)驗(yàn),選擇創(chuàng)新互聯(lián),為企業(yè)錦上添花!內(nèi)存區(qū)域劃分
類加載
何時(shí)觸發(fā)類加載?
雙親委派模型
GC
GC回收那部分內(nèi)存?
怎么回收?
怎么找垃圾(判定某個(gè)對(duì)象是否是垃圾)
具體怎么回收?
內(nèi)存區(qū)域劃分我的GitHub:Powerveil · GitHub
我的Gitee:Powercs12 (powercs12) - Gitee.com
皮卡丘每天學(xué)Java
JVM內(nèi)存區(qū)域大致分為四塊:堆、棧(虛擬機(jī)棧,本地方法棧)、程序計(jì)數(shù)器、方法區(qū)。
public class Test {
? ? ?// 成員變量
? ? ?public int c = 11;
? ? ?public Test d = new Test();
? ? ?// 靜態(tài)變量
? ? ?public static int e = 12;
? ? ?public static Test f = new Test();
??
? ? ?public static void main(String[] args) {
? ? ? ? ?// 局部變量
? ? ? ? ?int a = 10;
? ? ? ? ?Test b = new Test();
? ? }
?}
a,b為局部變量,在棧中存儲(chǔ);c,d為成員變量,在堆中存儲(chǔ);e,f為靜態(tài)變量,在方法區(qū)中存儲(chǔ)。
變量位置 | JVM位置 |
---|---|
局部變量 | 棧上 |
成員變量 | 堆上 |
靜態(tài)變量 | 方法區(qū)上 |
類加載大致分為五個(gè)過(guò)程:加載、連接、初始化,其中連接又分為:驗(yàn)證、準(zhǔn)備、解析三個(gè)過(guò)程。
以字符串為例
1.加載:找到.class文件,讀取文件內(nèi)容,并且按照.class規(guī)范的格式來(lái)解析
2.驗(yàn)證:檢查當(dāng)前的.class里的內(nèi)容格式是否符合要求
下圖為.class文件的定義,類似C語(yǔ)言的結(jié)構(gòu)體,左側(cè)是類型,右側(cè)是變量名。
u2代表兩個(gè)字節(jié)的無(wú)符號(hào)整數(shù),u4代表四個(gè)字節(jié)的無(wú)符號(hào)整數(shù),cp_info,field_info,method_info,attribute_info為類似.class文件類型的其他類型。
屬性 | 含義 |
---|---|
magic | 魔數(shù) |
minor_version | 最小版本號(hào) |
major_version | 大版本號(hào) |
constant_pool_count | 常量池個(gè)數(shù) |
constant_pool[constant_pool_count-1] | 常量池 |
access_flags | 類的訪問(wèn)權(quán)限和屬性 |
this_class | 表示此文件定義的類 |
super_class | 表示其父類 |
interfaces_count | 當(dāng)前類實(shí)現(xiàn)的接口數(shù)量 |
interfaces[interfaces_count] | 當(dāng)前類具體實(shí)現(xiàn)哪些接口 |
fields_count | 當(dāng)前類擁有的屬性個(gè)數(shù) |
fields[fields_count] | 當(dāng)前類具體擁有的屬性 |
methods_count | 當(dāng)前類擁有的方法個(gè)數(shù) |
methods[methods_count] | 當(dāng)前類具體擁有的方法 |
attributes_count | 當(dāng)前類的其他屬性個(gè)數(shù) |
attributes[attributes_count] | 當(dāng)前類的其他其他屬性 |
這里著重說(shuō)一下魔數(shù)
在計(jì)算機(jī)領(lǐng)域,魔數(shù)有兩個(gè)含義,一指用來(lái)判斷文件類型的魔數(shù);二指程序代碼中的魔數(shù),也稱魔法值。
這里主要說(shuō)第一種含義,不僅Java的.class文件有魔數(shù),其他文件也有魔數(shù),一個(gè)文件的類型不是取決于文件后綴名,本質(zhì)上卻決于該文件的魔數(shù)值。
3.準(zhǔn)備:給類里的靜態(tài)變量分配空間(并設(shè)置默認(rèn)值)
4.解析,初始化字符串常量,把符號(hào)引用替換成直接引用。
5.初始化,針對(duì)類進(jìn)行初始化,初始化靜態(tài)成員,執(zhí)行靜態(tài)代碼塊,并且加載父類...
何時(shí)觸發(fā)類加載?第一次使用到一個(gè)類的時(shí)候就會(huì)觸發(fā)加載(類似懶漢模式)。
1.創(chuàng)建這個(gè)類的實(shí)例
2.使用了類的靜態(tài)方法/靜態(tài)屬性
3.使用類的子類(加載子類會(huì)觸發(fā)加載父類)
注意第二條
訪問(wèn)類中的static final 成員時(shí),JVM會(huì)在編譯階段對(duì)類執(zhí)行編譯優(yōu)化,當(dāng)類中有static final修飾的基本數(shù)據(jù)類型和字符串類型時(shí),就會(huì)在編譯階段執(zhí)行初始化.
雙親委派模型JVM加載類,是由類加載器(class loader)這樣的模塊來(lái)負(fù)責(zé)的
JVM自帶了多個(gè)類加載器(程序員也可以自己實(shí)現(xiàn))
主要分為三類加載器
1.Bootstrap ClassLoader(負(fù)責(zé)加載標(biāo)準(zhǔn)庫(kù)中的類)
2.Extension ClassLoader(負(fù)責(zé)加載JVM擴(kuò)展的庫(kù)的類,Java規(guī)范里沒(méi)有寫(xiě)的,但是JVM實(shí)現(xiàn)出來(lái)了)
3.Application ClassLoader(負(fù)責(zé)加載自己的項(xiàng)目里的自定義類)
這三類加載器各自負(fù)責(zé)各自的片區(qū)(負(fù)責(zé)各自的一組目錄)
1.上述三個(gè)類加載器存在父子關(guān)系
2.進(jìn)行類加載的時(shí)候,輸入的內(nèi)容 全限定類名 java.util.Arrays
3.加載的時(shí)候,從Application ClassLoader開(kāi)始
4.某個(gè)類加載器開(kāi)始加載的時(shí)候,不會(huì)立即掃描自己負(fù)責(zé)的路徑,而是先把任務(wù)委托給 父 “類加載器” 先來(lái)進(jìn)行處理
5.找到最上面的Bootstrap ClassLoader 在往上,沒(méi)有父 類加載器了,自己加載
6.如果自己沒(méi)找到類,就交給自己的兒子,繼續(xù)加載。
7.如果一直找到最下面Application ClassLoader也沒(méi)有找到類,就會(huì)拋出一個(gè)"類沒(méi)找到"異常,類加載就失敗了,類似下圖
按照這個(gè)順序加載,大的好處在于:如果開(kāi)發(fā)者寫(xiě)了一個(gè)類,這這個(gè)類的全限定類名和標(biāo)準(zhǔn)庫(kù)里的類沖突了,(比如自己寫(xiě)一個(gè)全限定類名為java.util.Arrays的類),此時(shí)仍然保證類加載可以加載到標(biāo)準(zhǔn)庫(kù)的類,防止代碼加載錯(cuò)了帶來(lái)問(wèn)題。
演示一下
idea非常智能,沒(méi)有找到我自己寫(xiě)的Arrays,演示失敗
我嘗試先讓類導(dǎo)入再改包名
idea還是檢測(cè)出來(lái)了
GC垃圾回收(Garbage Collection)
寫(xiě)C語(yǔ)言代碼的時(shí)候,使用malloc申請(qǐng)內(nèi)存(動(dòng)態(tài)內(nèi)存申請(qǐng)),務(wù)必需要通過(guò)free來(lái)進(jìn)行釋放,如果不手動(dòng)free,這個(gè)內(nèi)存會(huì)一直持續(xù)到程序結(jié)束。造成空間上的浪費(fèi),而這些只用幾次就不使用,直到程序結(jié)束還釋放的空間就稱為垃圾。
手動(dòng)釋放,大的問(wèn)題在于容易忘記,造成內(nèi)存泄漏。內(nèi)存泄漏短時(shí)間內(nèi)不會(huì)出現(xiàn)問(wèn)題,就像一顆定時(shí)炸彈,不確定那個(gè)時(shí)候會(huì)造成程序崩潰。
于是程序員大佬就想出各種方案,其中GC(垃圾回收)就是一種主流的方案。許多語(yǔ)言使用了GC如,Java、Python、JavaScript、Golang、PHP等等。
Java程序員只需要負(fù)責(zé)申請(qǐng)內(nèi)存,釋放內(nèi)存的工作交給JVM來(lái)完成,JVM會(huì)自動(dòng)判定當(dāng)前的內(nèi)存什么時(shí)候需要釋放,認(rèn)為這個(gè)內(nèi)存不再使用了,就自動(dòng)釋放了。
GC回收那部分內(nèi)存?堆(GC主要就是針對(duì)堆來(lái)回收)、方法區(qū)(類對(duì)象,加載之后也不太會(huì)卸載)、棧(釋放時(shí)機(jī)確定,不必回收)、程序計(jì)數(shù)器(固定內(nèi)存空間,不必回收)。
GC中回收內(nèi)存,不是以"字節(jié)"為單位,而是以“對(duì)象”為單位
怎么回收?1.先找出垃圾(找出是誰(shuí)垃圾,沒(méi)錯(cuò),是我了)
2.再回收垃圾(釋放內(nèi)存)
怎么找垃圾(判定某個(gè)對(duì)象是否是垃圾)如果一個(gè)對(duì)象再也不用了,就說(shuō)明就是垃圾了。再Java中,對(duì)象的使用需要憑借引用,假設(shè)有一個(gè)對(duì)象已經(jīng)沒(méi)有任何引用能夠指向它了,這個(gè)對(duì)象自然就無(wú)法再被使用了,
最關(guān)鍵的要點(diǎn),通過(guò)引用來(lái)判定當(dāng)前對(duì)象是否還能被使用了,沒(méi)有引用指向就是為是無(wú)法被使用。
兩種典型的判斷對(duì)象是否存在引用的方法:引用計(jì)數(shù)[不是JVM采取的方法],可達(dá)性分析[是JVM采取的辦法]
引用計(jì)數(shù)
給每個(gè)對(duì)象都加上一個(gè)計(jì)數(shù)器,這個(gè)計(jì)數(shù)器就表示“當(dāng)前的對(duì)象有幾個(gè)引用”
每次多一個(gè)引用指向該對(duì)象,計(jì)數(shù)器就+1
每次少一個(gè)引用指向該對(duì)象,計(jì)數(shù)器就-1
(比如引用是一個(gè)局部變量,除了作用域?;蛘咭檬莻€(gè)成員變量,所在的對(duì)象被銷毀了)
當(dāng)引用計(jì)數(shù)器數(shù)值為0的時(shí)候,就說(shuō)明當(dāng)前這個(gè)對(duì)象已經(jīng)無(wú)人能夠使用了,此時(shí)就可以進(jìn)行釋放了
引用計(jì)數(shù)的優(yōu)點(diǎn):簡(jiǎn)單,容易實(shí)現(xiàn),執(zhí)行效率也比較高
缺點(diǎn)
1.空間利用率比較低,尤其是小對(duì)象 比如計(jì)數(shù)器是個(gè)int,如果你的對(duì)象本身里面只有一個(gè)int成員
2.可能會(huì)出現(xiàn)循環(huán)引用的情況
雖然當(dāng)前這兩個(gè)對(duì)象引用計(jì)數(shù)為1,但實(shí)際上是兩個(gè)對(duì)象再互相引用,此時(shí)外界的代碼仍然是無(wú)法訪問(wèn)和使用對(duì)象的,但是由于引用計(jì)數(shù)沒(méi)有成為0,這倆對(duì)象是無(wú)法進(jìn)行釋放的。
可達(dá)性分析
約定一些特定的變量,成為“GC roots”,每個(gè)一段時(shí)間,從GC roots出發(fā),進(jìn)行遍歷,看看當(dāng)前哪些變量是能夠被訪問(wèn)到的,能被訪問(wèn)到的變量就稱為“可達(dá)”,否則就是“不可達(dá)”
GC roots
棧上的變量
常量值應(yīng)用的對(duì)象
方法區(qū),引用類型的靜態(tài)變量
每一組都有一些變量
每個(gè)變量都可以視為起點(diǎn)
從這些起點(diǎn)出發(fā),盡可能遍歷,能夠找到所有訪問(wèn)到的對(duì)象
只要是通過(guò)上述root的方式訪問(wèn)到的對(duì)象,對(duì)象都是可達(dá)的。
具體怎么回收?標(biāo)記-清除法
先從堆首地址開(kāi)始遍歷,判斷該對(duì)象是垃圾后標(biāo)記為垃圾,第二次遍歷清除被標(biāo)記為垃圾標(biāo)志的垃圾
然后把對(duì)象對(duì)應(yīng)的內(nèi)存空間進(jìn)行釋放。
缺點(diǎn)
這種方式有一個(gè)大的問(wèn)題:內(nèi)存碎片。導(dǎo)致整個(gè)內(nèi)存“支離破碎”,比如上述每個(gè)黑色區(qū)域是1Kb,此時(shí)整個(gè)有4K的空閑空間,但是由于內(nèi)存是離散的,導(dǎo)致想申請(qǐng)2Kb的內(nèi)存空間(連續(xù)的)都申請(qǐng)不成功
復(fù)制算法
針對(duì)剛才所說(shuō)的內(nèi)存碎片問(wèn)題來(lái)進(jìn)行引入的方法
使用左側(cè)空間時(shí),右側(cè)不用;使用右側(cè)空間時(shí),左側(cè)不用。
不再是原地釋放了,而是把“非垃圾”(可以繼續(xù)使用的對(duì)象)拷貝到另外一側(cè),然后再把之前這一半整個(gè)釋放掉,內(nèi)存碎片就得到了妥善處理。
缺點(diǎn)
1.空間利用率更低了(用一半,丟一半)
2.如果一輪GC下來(lái),大部分對(duì)象要保留,只有少數(shù)對(duì)象要回收,這個(gè)時(shí)候復(fù)制開(kāi)銷就很大了。
標(biāo)記整理法
類似于順序表刪除元素搬運(yùn)操作,將后面元素依次搬運(yùn)到前面垃圾位置。
這種方式相對(duì)于上述發(fā)復(fù)制算法來(lái)說(shuō),空間利用率上來(lái)了,同時(shí)也還是能夠解決內(nèi)存碎片問(wèn)題,但是搬運(yùn)操作也是比較耗時(shí)的。
分代回收策略
上述三個(gè)方式,都不是十全十美,所以需要根據(jù)實(shí)際的場(chǎng)景,因地制宜的解決問(wèn)題。
根據(jù)對(duì)象不同的特點(diǎn),采取不同的回收方式
對(duì)象不同的特點(diǎn):根據(jù)對(duì)象年齡劃分
對(duì)象年齡:更具GC的輪次來(lái)算,有一組線程,周期性的掃描代碼里所有的對(duì)象,如果一個(gè)對(duì)象經(jīng)歷了一次GC而沒(méi)有被回收,就認(rèn)為年齡+1.
一個(gè)基本的經(jīng)驗(yàn)規(guī)律:如果一個(gè)對(duì)象壽命比較長(zhǎng)了,大概率還會(huì)活的更久(要被回收,早就被回收了)
例如許多東西都是短暫美好的,經(jīng)過(guò)時(shí)間的洗禮,少數(shù)經(jīng)典的東西才會(huì)被留下,哪些短暫的東西很短的時(shí)間就消逝了。
基于上述策略,就針對(duì)對(duì)象的年齡進(jìn)行了分類,把堆里的對(duì)象分成了:新生代(年齡小的對(duì)象,GC掃描的頻率較高)和老年代(年齡大的對(duì)象,GC掃描的頻率較低)
剛創(chuàng)建出來(lái)的對(duì)象進(jìn)入伊甸區(qū)
如果新對(duì)象熬過(guò)一輪GC,就通過(guò)復(fù)制算法,復(fù)制到生存區(qū)中,
生存區(qū)的對(duì)象也要經(jīng)歷GC的考研,每次熬過(guò)一輪GC,就通過(guò)復(fù)制算法拷貝到另一個(gè)生存區(qū)中,只要這個(gè)對(duì)象不消亡,就會(huì)在兩個(gè)生存區(qū)中間來(lái)回拷貝,每一輪拷貝,每一輪GC都會(huì)少選掉一大波對(duì)象。即同一時(shí)間只用一個(gè)生存區(qū)。
如果一個(gè)對(duì)象在生存區(qū)中反復(fù)堅(jiān)持了很多輪,還沒(méi)事,就會(huì)進(jìn)入老年代了。
如果對(duì)象來(lái)到了老年代,也不是完全的穩(wěn)定,也會(huì)定期進(jìn)行GC,只是頻率更低了,這里采取標(biāo)記整理的方式來(lái)處理老年代對(duì)象
上述規(guī)則還有個(gè)特殊情況!!!
如果對(duì)象是一個(gè)非常大的對(duì)象,則直接進(jìn)入老年代!!!
解釋:大對(duì)象進(jìn)行復(fù)制算法開(kāi)銷太大,既然一個(gè)很大的對(duì)象,好不容易創(chuàng)造出來(lái),看肯定不是立即就銷毀的。
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
網(wǎng)站標(biāo)題:JVM基本常識(shí)-創(chuàng)新互聯(lián)
URL標(biāo)題:http://jinyejixie.com/article28/egdcp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動(dòng)態(tài)網(wǎng)站、定制網(wǎng)站、網(wǎng)站設(shè)計(jì)公司、自適應(yīng)網(wǎng)站、網(wǎng)站導(dǎo)航、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容