JVM基本常識-創(chuàng)新互聯(lián)

目錄

創(chuàng)新互聯(lián)咨詢熱線:18980820575,為您提供成都網(wǎng)站建設(shè)網(wǎng)頁設(shè)計及定制高端網(wǎng)站建設(shè)服務(wù),創(chuàng)新互聯(lián)網(wǎng)頁制作領(lǐng)域10余年,包括成都活動板房等多個方面擁有多年的網(wǎng)站制作經(jīng)驗,選擇創(chuàng)新互聯(lián),為企業(yè)錦上添花!

內(nèi)存區(qū)域劃分

類加載

何時觸發(fā)類加載?

雙親委派模型

GC

GC回收那部分內(nèi)存?

怎么回收?

怎么找垃圾(判定某個對象是否是垃圾)

具體怎么回收?


我的GitHub:Powerveil · GitHub

我的Gitee:Powercs12 (powercs12) - Gitee.com

皮卡丘每天學(xué)Java

內(nèi)存區(qū)域劃分

JVM內(nèi)存區(qū)域大致分為四塊:堆、棧(虛擬機棧,本地方法棧)、程序計數(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為局部變量,在棧中存儲;c,d為成員變量,在堆中存儲;e,f為靜態(tài)變量,在方法區(qū)中存儲。

變量位置JVM位置
局部變量棧上
成員變量堆上
靜態(tài)變量方法區(qū)上

類加載

類加載大致分為五個過程:加載、連接、初始化,其中連接又分為:驗證、準備、解析三個過程。

以字符串為例

1.加載:找到.class文件,讀取文件內(nèi)容,并且按照.class規(guī)范的格式來解析

2.驗證:檢查當前的.class里的內(nèi)容格式是否符合要求

下圖為.class文件的定義,類似C語言的結(jié)構(gòu)體,左側(cè)是類型,右側(cè)是變量名。

u2代表兩個字節(jié)的無符號整數(shù),u4代表四個字節(jié)的無符號整數(shù),cp_info,field_info,method_info,attribute_info為類似.class文件類型的其他類型。

屬性含義
magic魔數(shù)
minor_version最小版本號
major_version大版本號
constant_pool_count常量池個數(shù)
constant_pool[constant_pool_count-1]常量池
access_flags類的訪問權(quán)限和屬性
this_class表示此文件定義的類
super_class表示其父類
interfaces_count當前類實現(xiàn)的接口數(shù)量
interfaces[interfaces_count]當前類具體實現(xiàn)哪些接口
fields_count當前類擁有的屬性個數(shù)
fields[fields_count]當前類具體擁有的屬性
methods_count當前類擁有的方法個數(shù)
methods[methods_count]當前類具體擁有的方法
attributes_count當前類的其他屬性個數(shù)
attributes[attributes_count]當前類的其他其他屬性

這里著重說一下魔數(shù)

在計算機領(lǐng)域,魔數(shù)有兩個含義,一指用來判斷文件類型的魔數(shù);二指程序代碼中的魔數(shù),也稱魔法值。

這里主要說第一種含義,不僅Java的.class文件有魔數(shù),其他文件也有魔數(shù),一個文件的類型不是取決于文件后綴名,本質(zhì)上卻決于該文件的魔數(shù)值。

3.準備:給類里的靜態(tài)變量分配空間(并設(shè)置默認值)

4.解析,初始化字符串常量,把符號引用替換成直接引用。

5.初始化,針對類進行初始化,初始化靜態(tài)成員,執(zhí)行靜態(tài)代碼塊,并且加載父類...

何時觸發(fā)類加載?

第一次使用到一個類的時候就會觸發(fā)加載(類似懶漢模式)。

1.創(chuàng)建這個類的實例

2.使用了類的靜態(tài)方法/靜態(tài)屬性

3.使用類的子類(加載子類會觸發(fā)加載父類)

注意第二條

訪問類中的static final 成員時,JVM會在編譯階段對類執(zhí)行編譯優(yōu)化,當類中有static final修飾的基本數(shù)據(jù)類型和字符串類型時,就會在編譯階段執(zhí)行初始化.

雙親委派模型

JVM加載類,是由類加載器(class loader)這樣的模塊來負責(zé)的

JVM自帶了多個類加載器(程序員也可以自己實現(xiàn))

主要分為三類加載器

1.Bootstrap ClassLoader(負責(zé)加載標準庫中的類)

2.Extension ClassLoader(負責(zé)加載JVM擴展的庫的類,Java規(guī)范里沒有寫的,但是JVM實現(xiàn)出來了)

3.Application ClassLoader(負責(zé)加載自己的項目里的自定義類)

這三類加載器各自負責(zé)各自的片區(qū)(負責(zé)各自的一組目錄)

1.上述三個類加載器存在父子關(guān)系

2.進行類加載的時候,輸入的內(nèi)容 全限定類名 java.util.Arrays

3.加載的時候,從Application ClassLoader開始

4.某個類加載器開始加載的時候,不會立即掃描自己負責(zé)的路徑,而是先把任務(wù)委托給 父 “類加載器” 先來進行處理

5.找到最上面的Bootstrap ClassLoader 在往上,沒有父 類加載器了,自己加載

6.如果自己沒找到類,就交給自己的兒子,繼續(xù)加載。

7.如果一直找到最下面Application ClassLoader也沒有找到類,就會拋出一個"類沒找到"異常,類加載就失敗了,類似下圖

按照這個順序加載,大的好處在于:如果開發(fā)者寫了一個類,這這個類的全限定類名和標準庫里的類沖突了,(比如自己寫一個全限定類名為java.util.Arrays的類),此時仍然保證類加載可以加載到標準庫的類,防止代碼加載錯了帶來問題。

演示一下

idea非常智能,沒有找到我自己寫的Arrays,演示失敗

我嘗試先讓類導(dǎo)入再改包名

idea還是檢測出來了

GC

垃圾回收(Garbage Collection)

寫C語言代碼的時候,使用malloc申請內(nèi)存(動態(tài)內(nèi)存申請),務(wù)必需要通過free來進行釋放,如果不手動free,這個內(nèi)存會一直持續(xù)到程序結(jié)束。造成空間上的浪費,而這些只用幾次就不使用,直到程序結(jié)束還釋放的空間就稱為垃圾。

手動釋放,大的問題在于容易忘記,造成內(nèi)存泄漏。內(nèi)存泄漏短時間內(nèi)不會出現(xiàn)問題,就像一顆定時炸彈,不確定那個時候會造成程序崩潰。

于是程序員大佬就想出各種方案,其中GC(垃圾回收)就是一種主流的方案。許多語言使用了GC如,Java、Python、JavaScript、Golang、PHP等等。

Java程序員只需要負責(zé)申請內(nèi)存,釋放內(nèi)存的工作交給JVM來完成,JVM會自動判定當前的內(nèi)存什么時候需要釋放,認為這個內(nèi)存不再使用了,就自動釋放了。

GC回收那部分內(nèi)存?

堆(GC主要就是針對堆來回收)、方法區(qū)(類對象,加載之后也不太會卸載)、棧(釋放時機確定,不必回收)、程序計數(shù)器(固定內(nèi)存空間,不必回收)。

GC中回收內(nèi)存,不是以"字節(jié)"為單位,而是以“對象”為單位

怎么回收?

1.先找出垃圾(找出是誰垃圾,沒錯,是我了)

2.再回收垃圾(釋放內(nèi)存)

怎么找垃圾(判定某個對象是否是垃圾)

如果一個對象再也不用了,就說明就是垃圾了。再Java中,對象的使用需要憑借引用,假設(shè)有一個對象已經(jīng)沒有任何引用能夠指向它了,這個對象自然就無法再被使用了,

最關(guān)鍵的要點,通過引用來判定當前對象是否還能被使用了,沒有引用指向就是為是無法被使用。

兩種典型的判斷對象是否存在引用的方法:引用計數(shù)[不是JVM采取的方法],可達性分析[是JVM采取的辦法]

引用計數(shù)

給每個對象都加上一個計數(shù)器,這個計數(shù)器就表示“當前的對象有幾個引用”

每次多一個引用指向該對象,計數(shù)器就+1

每次少一個引用指向該對象,計數(shù)器就-1

(比如引用是一個局部變量,除了作用域?;蛘咭檬莻€成員變量,所在的對象被銷毀了)

當引用計數(shù)器數(shù)值為0的時候,就說明當前這個對象已經(jīng)無人能夠使用了,此時就可以進行釋放了

引用計數(shù)的優(yōu)點:簡單,容易實現(xiàn),執(zhí)行效率也比較高

缺點

1.空間利用率比較低,尤其是小對象 比如計數(shù)器是個int,如果你的對象本身里面只有一個int成員

2.可能會出現(xiàn)循環(huán)引用的情況

雖然當前這兩個對象引用計數(shù)為1,但實際上是兩個對象再互相引用,此時外界的代碼仍然是無法訪問和使用對象的,但是由于引用計數(shù)沒有成為0,這倆對象是無法進行釋放的。

可達性分析

約定一些特定的變量,成為“GC roots”,每個一段時間,從GC roots出發(fā),進行遍歷,看看當前哪些變量是能夠被訪問到的,能被訪問到的變量就稱為“可達”,否則就是“不可達”

GC roots

  • 棧上的變量

  • 常量值應(yīng)用的對象

  • 方法區(qū),引用類型的靜態(tài)變量

每一組都有一些變量

每個變量都可以視為起點

從這些起點出發(fā),盡可能遍歷,能夠找到所有訪問到的對象

只要是通過上述root的方式訪問到的對象,對象都是可達的。

具體怎么回收?

標記-清除法

先從堆首地址開始遍歷,判斷該對象是垃圾后標記為垃圾,第二次遍歷清除被標記為垃圾標志的垃圾

然后把對象對應(yīng)的內(nèi)存空間進行釋放。

缺點

這種方式有一個大的問題:內(nèi)存碎片。導(dǎo)致整個內(nèi)存“支離破碎”,比如上述每個黑色區(qū)域是1Kb,此時整個有4K的空閑空間,但是由于內(nèi)存是離散的,導(dǎo)致想申請2Kb的內(nèi)存空間(連續(xù)的)都申請不成功

復(fù)制算法

針對剛才所說的內(nèi)存碎片問題來進行引入的方法

使用左側(cè)空間時,右側(cè)不用;使用右側(cè)空間時,左側(cè)不用。

不再是原地釋放了,而是把“非垃圾”(可以繼續(xù)使用的對象)拷貝到另外一側(cè),然后再把之前這一半整個釋放掉,內(nèi)存碎片就得到了妥善處理。

缺點

1.空間利用率更低了(用一半,丟一半)

2.如果一輪GC下來,大部分對象要保留,只有少數(shù)對象要回收,這個時候復(fù)制開銷就很大了。

標記整理法

類似于順序表刪除元素搬運操作,將后面元素依次搬運到前面垃圾位置。

這種方式相對于上述發(fā)復(fù)制算法來說,空間利用率上來了,同時也還是能夠解決內(nèi)存碎片問題,但是搬運操作也是比較耗時的。

分代回收策略

上述三個方式,都不是十全十美,所以需要根據(jù)實際的場景,因地制宜的解決問題。

根據(jù)對象不同的特點,采取不同的回收方式

對象不同的特點:根據(jù)對象年齡劃分

對象年齡:更具GC的輪次來算,有一組線程,周期性的掃描代碼里所有的對象,如果一個對象經(jīng)歷了一次GC而沒有被回收,就認為年齡+1.

一個基本的經(jīng)驗規(guī)律:如果一個對象壽命比較長了,大概率還會活的更久(要被回收,早就被回收了)

例如許多東西都是短暫美好的,經(jīng)過時間的洗禮,少數(shù)經(jīng)典的東西才會被留下,哪些短暫的東西很短的時間就消逝了。

基于上述策略,就針對對象的年齡進行了分類,把堆里的對象分成了:新生代(年齡小的對象,GC掃描的頻率較高)和老年代(年齡大的對象,GC掃描的頻率較低)

剛創(chuàng)建出來的對象進入伊甸區(qū)

如果新對象熬過一輪GC,就通過復(fù)制算法,復(fù)制到生存區(qū)中,

生存區(qū)的對象也要經(jīng)歷GC的考研,每次熬過一輪GC,就通過復(fù)制算法拷貝到另一個生存區(qū)中,只要這個對象不消亡,就會在兩個生存區(qū)中間來回拷貝,每一輪拷貝,每一輪GC都會少選掉一大波對象。即同一時間只用一個生存區(qū)。

如果一個對象在生存區(qū)中反復(fù)堅持了很多輪,還沒事,就會進入老年代了。

如果對象來到了老年代,也不是完全的穩(wěn)定,也會定期進行GC,只是頻率更低了,這里采取標記整理的方式來處理老年代對象

上述規(guī)則還有個特殊情況!!!

如果對象是一個非常大的對象,則直接進入老年代!!!

解釋:大對象進行復(fù)制算法開銷太大,既然一個很大的對象,好不容易創(chuàng)造出來,看肯定不是立即就銷毀的。

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)站標題:JVM基本常識-創(chuàng)新互聯(lián)
URL標題:http://muchs.cn/article28/egdcp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、定制網(wǎng)站網(wǎng)站設(shè)計公司、自適應(yīng)網(wǎng)站網(wǎng)站導(dǎo)航、靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運營