欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)邀請(qǐng)碼778899分享:圖解 畫圖理解JVM相關(guān)內(nèi)容

柚子快報(bào)邀請(qǐng)碼778899分享:圖解 畫圖理解JVM相關(guān)內(nèi)容

http://yzkb.51969.com/

文章目錄

1. JVM視角下,內(nèi)存劃分2. 類內(nèi)存分布硬核詳解1. 獲取堆內(nèi)存參數(shù)2. 掃描堆內(nèi)存,定位實(shí)例3. 查看實(shí)例所在地址的數(shù)據(jù)4. 找到實(shí)例所指向的類信息的地址5. 查看class信息6. 結(jié)論

3. Java的對(duì)象創(chuàng)建流程4. 垃圾判別算法4.1 引用計(jì)數(shù)法4.2 可達(dá)性分析算法

5. 垃圾收集算法5.1 標(biāo)記-清除算法5.2 標(biāo)記-復(fù)制算法5.3 標(biāo)記-整理算法

1. JVM視角下,內(nèi)存劃分

tip: 額外補(bǔ)充

在以“分代設(shè)計(jì)”為主導(dǎo)的堆內(nèi)存,其控件劃分大致如上圖所示。但G1垃圾回收期為分解,后續(xù)的內(nèi)存設(shè)計(jì)并沒(méi)有都參考分代理論,因此jdk8以后(G1大規(guī)模運(yùn)用在jdk8之后),內(nèi)存劃分有待商榷堆雖然是線程共享的,但他可以為線程劃分緩沖區(qū)——Thread Local Allocation Buffer,TLAB。TLAB是線程私有的。但無(wú)論怎么劃分,堆都是存儲(chǔ)對(duì)象實(shí)例直接內(nèi)存:屬于操作系統(tǒng)本地內(nèi)存,不歸JVM管理。因此GC對(duì)他無(wú)效

2. 類內(nèi)存分布硬核詳解

既然是硬核,不來(lái)點(diǎn)內(nèi)存轟炸是對(duì)不起硬核兩字。

下文主要講述一個(gè)類在創(chuàng)建過(guò)程中,可能會(huì)涉及到的所有類在內(nèi)存的分布情況。包括JVM層面的instanceKlass,Java層面的Test實(shí)例,Test.class

下文內(nèi)容比較硬核,請(qǐng)讀者酌情閱讀。另外,底層指針?lè)治隹赡艽嬖诩劼?,歡迎讀者友善指出

讓我們開始!

demo代碼如下

package com.xhf.test;

// -XX:+UseSerialGC -Xmn10M -XX:-UseCompressedOops

public class TestDemo {

public static void main(String[] args) {

new Test();

while (true) {}

}

}

package com.xhf.test;

public class Test {

private static Integer a;

private Integer b;

private int c;

public int d;

private void func() {}

public void func2() {}

}

1. 獲取堆內(nèi)存參數(shù)

打開HSDB,掃描堆的整體內(nèi)存范圍 universe

Heap Parameters:

Gen 0: eden [0x0000000080000000,0x00000000803845a8,0x0000000080800000) space capacity = 8388608, 43.96257400512695 used

from [0x0000000080800000,0x0000000080800000,0x0000000080900000) space capacity = 1048576, 0.0 used

to [0x0000000080900000,0x0000000080900000,0x0000000080a00000) space capacity = 1048576, 0.0 usedInvocations: 0

Gen 1: old [0x0000000080a00000,0x0000000080a00000,0x000000008fe00000) space capacity = 255852544, 0.0 usedInvocations: 0

其它信息我們可以不用關(guān)注,只需要知道,eden區(qū)的范圍是0x0000000080000000 0x0000000080800000,絕大多數(shù)情況下,對(duì)象的空間有限劃分在eden區(qū)域。因此,我們想要探查Test示例相關(guān)內(nèi)存地址,需要掃描eden區(qū)域

2. 掃描堆內(nèi)存,定位實(shí)例

scanoops 0x0000000080000000 0x0000000080800000 com.xhf.test.Test

hsdb> scanoops 0x0000000080000000 0x0000000080800000 com.xhf.test.Test

0x000000008023e2d0 com/xhf/test/Test

主程序運(yùn)行new Test();,他的實(shí)例對(duì)象被劃分在0x000000008023e2d0地址

3. 查看實(shí)例所在地址的數(shù)據(jù)

inspect 0x000000008023e2d0

hsdb> inspect 0x000000008023e2d0

instance of Oop for com/xhf/test/Test @ 0x000000008023e2d0 @ 0x000000008023e2d0 (size = 32)

_mark: 1

_metadata._klass: InstanceKlass for com/xhf/test/Test

b: null null

c: 0

d: 0

在控制臺(tái)上通過(guò)指令,查看不到最全面的信息,通過(guò)Tools->inspector創(chuàng)建可視化窗口,可以查看最全面的信息,具體如下

通過(guò)上述兩幅圖,我們可以返現(xiàn)很多有趣的細(xì)節(jié)

_mark字段,mark其實(shí)就是markword,對(duì)象頭的意思。markword能夠存儲(chǔ)相當(dāng)豐富的信息,比如分代年齡,gc次數(shù),偏向鎖,重鎖等等信息。_metadata._klass,類型指針,指向類型com.xhf.test.Test.class。該字段用于表示當(dāng)前實(shí)例是哪個(gè)類的實(shí)例b, c, d:3個(gè)字段屬于oop,但a不屬于oop,a屬于Test.class,因?yàn)樗庆o態(tài)變量。此外,b這個(gè)Object被賦值null,c,d兩個(gè)基本int類型賦值為0

4. 找到實(shí)例所指向的類信息的地址

我們找到Test oop,但沒(méi)有找到存儲(chǔ)Test類信息的數(shù)據(jù)地址。inspect無(wú)法直接看到_metadata._klass指向的地址,我們通過(guò)內(nèi)存掃描,直接查看內(nèi)存數(shù)據(jù)

mem 0x000000008023e2d0 2 :查看0x000000008023e2d0地址,偏移2個(gè)單位(8bit)

hsdb> mem 0x000000008023e2d0 2

0x000000008023e2d0: 0x0000000000000001

0x000000008023e2d8: 0x0000000013ff3400

0x0000000013ff3400,就是oop指向的Test類信息所在地址

注意,筆者這里并沒(méi)有說(shuō)明0x0000000013ff3400是Test.class類對(duì)象的地址

5. 查看class信息

如下圖所示,0x0000000013ff3400才是class真正的信息,這也被稱為元信息,被JVM存儲(chǔ)在meta space中

!?。⌒枰⒁獾氖?,0x0000000013ff3400地址上的內(nèi)容不是Java意義上的Test.class這個(gè)類

筆者為什么會(huì)這么說(shuō)呢?原因是JVM內(nèi)部采用C++的instanceKlass描述 Java類,并且會(huì)將instanceKlass分配到meta space

而instanceKlass有個(gè)叫做_java_mirror的字段,它指向的才是Java類的Class對(duì)象

本例中就是Test.class這個(gè)對(duì)象

我們監(jiān)視這個(gè)地址inspect 0x000000008023e210

hsdb> inspect 0x000000008023e210

instance of Oop for java/lang/Class @ 0x000000008023e210 @ 0x000000008023e210 (size = 168)

a: null null

發(fā)現(xiàn)_java_mirror指向的對(duì)象,是java/lang/Class類(Test.class),并且大小168bit

我們掃描0x000000008023e210往后的168bit(21個(gè)8bit)內(nèi)存空間

mem 0x000000008023e210 21

hsdb> mem 0x000000008023e210 21

0x000000008023e210: 0x0000000000000001

0x000000008023e218: 0x0000000013c03ed0

0x000000008023e220: 0x0000000000000000

0x000000008023e228: 0x0000000000000000

0x000000008023e230: 0x0000000000000000

0x000000008023e238: 0x00000000800dba38

0x000000008023e240: 0x0000000000000000

0x000000008023e248: 0x0000000000000000

0x000000008023e250: 0x0000000000000000

0x000000008023e258: 0x0000000000000000

0x000000008023e260: 0x0000000000000000

0x000000008023e268: 0x0000000000000000

0x000000008023e270: 0x0000000000000000

0x000000008023e278: 0x0000000080239560

0x000000008023e280: 0x0000000000000000

0x000000008023e288: 0x0000000000000000

0x000000008023e290: 0x0000000013ff3400

0x000000008023e298: 0x0000000000000000

0x000000008023e2a0: 0x0000001500000000

0x000000008023e2a8: 0x0000000000000001

0x000000008023e2b0: 0x0000000000000000

發(fā)現(xiàn)內(nèi)存地址為0x000000008023e290時(shí),存放的數(shù)據(jù)是:0x0000000013ff3400

而0x0000000013ff3400的內(nèi)容,恰好是instanceKlass所在地址。

6. 結(jié)論

基于上述分析,我們得出如下結(jié)論:

Test實(shí)例 -> Test instanceKlass <-> Test.class

文字枯燥乏味,看圖就好理解了

3. Java的對(duì)象創(chuàng)建流程

有了第2節(jié)的基礎(chǔ),第三節(jié)的分析自然就簡(jiǎn)單多了。

具體流程直接上圖

這個(gè)流程中,具體的內(nèi)存情況如下

tip: 嚴(yán)格來(lái)說(shuō),上圖存在一定的問(wèn)題。 由第2節(jié)可知,實(shí)例的指針指向的是instanceKlass,而非class對(duì)象。這里這么處理是為了方便畫圖。 而且,instanceKlass擁有class對(duì)象的指針,實(shí)例可以通過(guò)instanceKlass找到class對(duì)象,只是需要兩次指針跳躍,所以上圖繪制方式其實(shí)也并無(wú)太大問(wèn)題

4. 垃圾判別算法

4.1 引用計(jì)數(shù)法

給對(duì)象增加計(jì)數(shù)器,當(dāng)計(jì)數(shù)器為0,表示對(duì)象不再被引用??梢援?dāng)作垃圾被垃圾清除器清理

這種算法的缺陷很明顯,一方面開銷大,JVM需要維護(hù)所有對(duì)象的引用計(jì)數(shù)器;另一方面,無(wú)法解決循環(huán)引用的問(wèn)題

4.2 可達(dá)性分析算法

以GC Root根節(jié)點(diǎn)的集合,作為起始點(diǎn)。按照對(duì)象之間的引用關(guān)系向下遍歷,如果某個(gè)對(duì)象無(wú)法和GC Root關(guān)聯(lián),那么我們認(rèn)為該對(duì)象是不可達(dá)的,可以當(dāng)作垃圾被回收

5. 垃圾收集算法

在講解回收算法前,我們需要補(bǔ)充一些分代理論的基礎(chǔ)知識(shí)

大部分對(duì)象都是朝生幕死,創(chuàng)建出來(lái)很快就被回收如果一個(gè)對(duì)象經(jīng)歷了多次垃圾回收,那么該對(duì)象可以被認(rèn)為是長(zhǎng)時(shí)間存活的對(duì)象

曾經(jīng)有個(gè)組織做過(guò)調(diào)查,98%的對(duì)象活不過(guò)一輪垃圾回收

考慮到對(duì)象存活時(shí)間長(zhǎng)短存在差異,我們可以大致將堆內(nèi)存劃分為兩塊空間

新生代(Young Generation)老年代(Old Generation)

新生代存放壽命短的對(duì)象;老年代存放長(zhǎng)命的對(duì)象。這樣在做垃圾回收時(shí),可以根據(jù)不同區(qū)域?qū)ο蟠婊钐攸c(diǎn)做出不一樣的垃圾回收策略,以此提高運(yùn)行效率

5.1 標(biāo)記-清除算法

標(biāo)記清楚算法是最基礎(chǔ)的垃圾回收算法,后續(xù)的算法基本都是在此基礎(chǔ)上進(jìn)行改進(jìn)。

該算法的核心是

標(biāo)記垃圾(可達(dá)性分析算法)清除垃圾

標(biāo)記-清除算法執(zhí)行流程如上圖所示

上述算法存在以下兩個(gè)缺陷

算法效率不穩(wěn)定:如果內(nèi)存中存在大量需要清除的垃圾,JVM需要執(zhí)行多次的清除操作;反之,如果垃圾數(shù)量較少,JVM執(zhí)行清除操作次數(shù)就少空間碎片:當(dāng)JVM執(zhí)行清除操作后,會(huì)存在大量?jī)?nèi)存碎片,內(nèi)存中使用的空間不連續(xù)。這極大的降低了內(nèi)存利用率,提高了內(nèi)存申請(qǐng)的難度

5.2 標(biāo)記-復(fù)制算法

標(biāo)記-復(fù)制算法,將內(nèi)存劃分為等大的兩個(gè)空間,一個(gè)空間用于存放對(duì)象,另一個(gè)空間用于預(yù)留。

當(dāng)需要進(jìn)行內(nèi)存清除時(shí),操作異常容易,因?yàn)閮蓚€(gè)區(qū)間在同一時(shí)刻只有一個(gè)區(qū)間存在使用的對(duì)象,因此只需要將存放對(duì)象的空間中,存活的對(duì)象復(fù)制到預(yù)留空間,然后清除原有空間的所有內(nèi)容,即可完成垃圾回收

該算法讓JVM只需要關(guān)注存活的對(duì)象,如果存活對(duì)象少,那么復(fù)制操作少,效率高,因此標(biāo)記-復(fù)制算法一般用于Eden區(qū)域的垃圾回收。此外,該算法成功解決了內(nèi)存碎片的問(wèn)題

但顯而易見,該算法帶來(lái)了另一個(gè)問(wèn)題

內(nèi)存利用率低:該算法需要額外的空間進(jìn)行存儲(chǔ),比標(biāo)記清除算法大了1倍的空間

5.3 標(biāo)記-整理算法

該算法就是在標(biāo)記-清除的基礎(chǔ)上,增加了整理的操作。對(duì)于清除后的內(nèi)存空間,該算法會(huì)通過(guò)移動(dòng)已使用的空間,讓內(nèi)存的使用再次連續(xù)

該算法解決了內(nèi)存碎片問(wèn)題,但移動(dòng)存活對(duì)象這個(gè)操作引入了新的問(wèn)題。就比如原先對(duì)象A引用了對(duì)象B,現(xiàn)在B的地址修改了,A如何感知到。此外,在移動(dòng)過(guò)程中,需要暫停用戶線程(Stop the world),因此需要移動(dòng)的對(duì)象數(shù)量要盡可能少,以此減少stop the world的時(shí)間

柚子快報(bào)邀請(qǐng)碼778899分享:圖解 畫圖理解JVM相關(guān)內(nèi)容

http://yzkb.51969.com/

參考鏈接

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/18873835.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄