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

目錄

柚子快報(bào)激活碼778899分享:JVM基礎(chǔ)知識(shí)整理

柚子快報(bào)激活碼778899分享:JVM基礎(chǔ)知識(shí)整理

http://yzkb.51969.com/

JVM相關(guān)基礎(chǔ)知識(shí)

一、JVM基礎(chǔ)1、java從編譯到執(zhí)行

二、類加載器1、類的加載1.1 類加載過(guò)程1.2 什么情況下會(huì)對(duì)類進(jìn)行初始化?1.3 new 一個(gè)對(duì)象的過(guò)程是怎樣的?

2、雙親委派模型2.1 模型組成2.2 工作原理2.3 優(yōu)點(diǎn)2.4.類加載器的加載過(guò)程源碼2.5 自定義類加載器的實(shí)現(xiàn)2.6 懶加載

三、JVM運(yùn)行數(shù)據(jù)區(qū)1、JVM運(yùn)行數(shù)據(jù)區(qū)可分為:方法區(qū)、堆、本地方法棧、虛擬機(jī)棧和程序計(jì)數(shù)器。2、一些補(bǔ)充2.1 介紹一下方法區(qū)2.2 對(duì)象一定分配在堆中嗎?

四、垃圾回收機(jī)制1、什么是新生代、老年代和永久代1.1 新生代1.2 老年代1.3 永久代

2、如何對(duì)象是否存活3、有哪些GC4、垃圾回收算法4.1 標(biāo)記清除算法4.2 復(fù)制算法:4.3 標(biāo)記整理算法4.4 分代算法

五、垃圾回收器1、Serial + Serial Old2、Parallel Scavenge + Parallel Old3、ParNew + CMS4、G1垃圾收集器

一、JVM基礎(chǔ)

1、java從編譯到執(zhí)行

一個(gè)x.java文件通過(guò)執(zhí)行javac變?yōu)閤.class文件,然后被ClassLoader加載到內(nèi)存中,通過(guò)java類庫(kù)中的一部分類(如:Object,String等)也會(huì)被加載到內(nèi)存中。Java即是編譯型的,也是解釋型語(yǔ)言,即混合型語(yǔ)言。常用代碼會(huì)被JIT即時(shí)編譯,提高效率??偟膩?lái)說(shuō)Java更接近解釋型語(yǔ)言。Java是跨平臺(tái)語(yǔ)言,JVM是跨語(yǔ)言平臺(tái)(只要是.class文件就能執(zhí)行)。JDK是Java開(kāi)發(fā)工具包;JRE是Java運(yùn)行環(huán)境;JVM是Java虛擬機(jī)。JDK包含JRE,JRE包含JVM。

二、類加載器

1、類的加載

1.1 類加載過(guò)程

loading (加載) —> linking(驗(yàn)證 —> 準(zhǔn)備 —> 解析) —> initializing(初始化)

加載:將java文件編譯成class文件。驗(yàn)證:校驗(yàn)class文件是否符合class文件的規(guī)范。準(zhǔn)備:為靜態(tài)變量分配空間,則在此階段分配默認(rèn)值。解析:將常量池中的符號(hào)引用替換為直接引用的過(guò)程。(有一部分符號(hào)引用會(huì)在使用時(shí)轉(zhuǎn)換為直接引用)初始化:執(zhí)行初始化方法的過(guò)程。加載靜態(tài)代碼塊,為靜態(tài)成員變量分配初始值等。

1.2 什么情況下會(huì)對(duì)類進(jìn)行初始化?

jvm執(zhí)行new指令時(shí)。初始化一個(gè)類,但其父類未被初始化時(shí),會(huì)優(yōu)先初始化父類。虛擬機(jī)啟動(dòng)時(shí),用戶需要定義一個(gè)執(zhí)行的主類即main()方法,會(huì)優(yōu)先初始化此類。首次訪問(wèn)此類的靜態(tài)變量或者靜態(tài)方法時(shí)使用java.lang.reflect包下的方法進(jìn)行反射調(diào)用如Class.forName()方法等

1.3 new 一個(gè)對(duì)象的過(guò)程是怎樣的?

如:T t = new T();

類的加載申請(qǐng)內(nèi)存(賦默認(rèn)值)調(diào)用構(gòu)造方法(賦初始值)指針指向內(nèi)存(賦值給t)

這里需要注意,在沒(méi)有volatile的情況下,3和4可能會(huì)發(fā)生指令重排序,即t先指向內(nèi)存,后賦初始值。 可能會(huì)導(dǎo)致另一個(gè)線程拿到的值為默認(rèn)值而非正確的初始化的值。(單例模式為什么要用volatile修飾)

2、雙親委派模型

2.1 模型組成

啟動(dòng)類加載器:c++實(shí)現(xiàn)擴(kuò)展類加載器應(yīng)用程序類加載器自定義加載器

2.2 工作原理

當(dāng)一個(gè)類需要被加載的時(shí)候,它不會(huì)直接執(zhí)行類加載,而是先把這個(gè)請(qǐng)求委托給父類加載器,直到把這個(gè)請(qǐng)求傳遞到啟動(dòng)類加載器。如果父類加載器無(wú)法完成此次類加載,則會(huì)讓其子類嘗試執(zhí)行類加載。

2.3 優(yōu)點(diǎn)

避免類的重復(fù)加載。避免Java的核心API被篡改。

2.4.類加載器的加載過(guò)程源碼

在loadClass中,會(huì)通過(guò)類似遞歸的方式自底向上地檢查父加載器是否已經(jīng)加載此類,如果全部沒(méi)有加載,則開(kāi)始自頂向下地嘗試加載。如果最終仍然加載失敗,則拋出ClassNotFoundException。

// java.lang.ClassLoader

// 類加載過(guò)程源碼

protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException {

synchronized (getClassLoadingLock(name)) {

// 校驗(yàn)類是否已經(jīng)被加載

Class c = findLoadedClass(name);

if (c == null) {

try {

if (parent != null) {

// 雙親委派,找父加載器去檢查加載。即自底向上地檢查。

c = parent.loadClass(name, false);

} else {

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

}

if (c == null) {

// 上面沒(méi)有從緩存中找到加載信息,只能自己加載。即自頂向下地嘗試加載。

// 如果未被重寫,該方法直接拋出ClassNotFoundException。

// 所以實(shí)現(xiàn)自定義類加載器的核心是重寫此方法。

c = findClass(name);

}

}

if (resolve) {

resolveClass(c);

}

}

return c;

}

2.5 自定義類加載器的實(shí)現(xiàn)

繼承ClassLoader,重寫其findClass方法。通過(guò)name構(gòu)造文件絕對(duì)路徑讀取文件。創(chuàng)建文件字節(jié)輸入流。創(chuàng)建字節(jié)數(shù)組輸出流。讀取輸入流,將數(shù)據(jù)寫入到輸出流。將字節(jié)數(shù)組輸出流裝換成二進(jìn)制字節(jié)數(shù)組。調(diào)用ClassLoader的defineClass()方法用字節(jié)數(shù)組構(gòu)造clazz對(duì)象。

public class MyClassLoader extends ClassLoader {

@Override

protected Class findClass(String name) throws ClassNotFoundException {

// 這里通過(guò)入?yún)?name 構(gòu)造出文件的絕對(duì)路徑來(lái)獲取file。

File file = new File("");

try {

// 創(chuàng)建文件字節(jié)輸入流

FileInputStream fileInputStream = new FileInputStream(file);

// 創(chuàng)建字節(jié)數(shù)組輸出流

ByteArrayOutputStream byteArrayInputStream = new ByteArrayOutputStream();

int b;

while ((b = fileInputStream.read()) != 0) {

// 讀取輸入流,將數(shù)據(jù)寫入到輸出流

byteArrayInputStream.write(b);

}

// 將字節(jié)數(shù)組輸出流裝換成二進(jìn)制字節(jié)數(shù)組

byte[] bytes = byteArrayInputStream.toByteArray();

byteArrayInputStream.close();

fileInputStream.close();

// 調(diào)用ClassLoader的defineClass()方法用字節(jié)數(shù)組構(gòu)造clazz對(duì)象

return defineClass(name, bytes, 0, bytes.length);

} catch (Exception e) {

e.printStackTrace();

}

return super.findClass(name);

}

}

自定義類加載器的使用也非常簡(jiǎn)單,即反射。

public static void main(String[] args) throws Exception {

ClassLoader classLoader = new MyClassLoader();

Class clazz = classLoader.loadClass("");

Object o = clazz.newInstance();

}

2.6 懶加載

懶加載其實(shí)就是按需加載,即當(dāng)對(duì)象需要用到的時(shí)候再去加載相關(guān)的對(duì)象。

三、JVM運(yùn)行數(shù)據(jù)區(qū)

1、JVM運(yùn)行數(shù)據(jù)區(qū)可分為:方法區(qū)、堆、本地方法棧、虛擬機(jī)棧和程序計(jì)數(shù)器。

方法區(qū)(Method Area):線程共有,主要用于存放類文件信息,靜態(tài)變量,常量以及即時(shí)編譯(JIT)后的代碼等數(shù)據(jù)。堆(Heap):線程共有,JVM中內(nèi)存最大的一塊, 主要用于存放對(duì)象實(shí)例,可分為新生代和老年代,是GC的主要區(qū)域。虛擬機(jī)棧(JVM Stacks):線程私有,主要存放棧幀。每個(gè)方法執(zhí)行時(shí)都會(huì)在棧中創(chuàng)建一個(gè)棧幀,棧幀是由局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接和返回地址組成。動(dòng)態(tài)鏈接指動(dòng)態(tài)將常量池中符號(hào)引用轉(zhuǎn)化為直接引用。本地方法棧(Native Method Stacks):線程私有,專門為JVM調(diào)用C和C++編寫的native方法服務(wù)。程序計(jì)數(shù)器(Program Counter Register):線程私有,用于保存當(dāng)前正在執(zhí)行的線程的字節(jié)碼地址。因?yàn)榫€程不具備記憶功能,所以需要程序計(jì)數(shù)器告訴線程該執(zhí)行哪一條字節(jié)碼。

2、一些補(bǔ)充

2.1 介紹一下方法區(qū)

方法區(qū)并不真實(shí)存在,屬于 Java 虛擬機(jī)規(guī)范中的一個(gè)邏輯概念,用于存儲(chǔ)已被 JVM 加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等。

在 HotSpot 虛擬機(jī)中,方法區(qū)的實(shí)現(xiàn)稱為永久代(PermGen),但在 Java 8 及之后的版本中,已經(jīng)被元空間(Metaspace)所替代,方法區(qū)的內(nèi)存大小取決于系統(tǒng)內(nèi)存的大小。

2.2 對(duì)象一定分配在堆中嗎?

隨著 JIT 編譯期的發(fā)展與逃逸分析技術(shù)逐漸成熟,所有的對(duì)象都分配到堆上也漸漸變得不那么“絕對(duì)”了。其實(shí),在編譯期間,JIT 會(huì)對(duì)代碼做很多優(yōu)化。其中有一部分優(yōu)化的目的就是減少內(nèi)存堆分配壓力,其中一種重要的技術(shù)叫做逃逸分析。

逃逸分析(Escape Analysis)技術(shù)

編譯器可能會(huì)將一些原本應(yīng)該在堆上分配的對(duì)象優(yōu)化為在棧上分配。這通常發(fā)生在對(duì)象的作用域明確并且不會(huì)逃逸出它的創(chuàng)建方法時(shí)。

逃逸分析的好處

棧上分配:如果確定一個(gè)對(duì)象不會(huì)逃逸到線程之外,那么久可以考慮將這個(gè)對(duì)象在棧上分配,對(duì)象占用的內(nèi)存隨著棧幀出棧而銷毀,這樣一來(lái),垃圾收集的壓力就降低很多。 同步消除:線程同步本身是一個(gè)相對(duì)耗時(shí)的過(guò)程,如果逃逸分析能夠確定一個(gè)變量不會(huì)逃逸出線程,無(wú)法被其他線程訪問(wèn),那么這個(gè)變量的讀寫肯定就不會(huì)有競(jìng)爭(zhēng), 對(duì)這個(gè)變量實(shí)施的同步措施也就可以安全地消除掉

四、垃圾回收機(jī)制

1、什么是新生代、老年代和永久代

1.1 新生代

主要用于存放新生的對(duì)象,占據(jù)堆內(nèi)存的1/3。由于頻繁創(chuàng)建對(duì)象,新生代會(huì)進(jìn)行頻繁的Minor GC。新生代分為三塊區(qū)域:Eden、ServiceFrom和ServiceTo。

Eden區(qū):新創(chuàng)建的對(duì)象會(huì)被放入Eden區(qū),如果對(duì)象過(guò)大則直接分配老年代。當(dāng)Eden區(qū)內(nèi)存不夠時(shí)會(huì)觸發(fā)Minor GC,而大多數(shù)對(duì)象都是朝生夕死,對(duì)于存活對(duì)象則是進(jìn)入ServiceTo區(qū)或ServiceFrom區(qū)。ServiceTo:一次Minor GC后Eden區(qū)或ServiceFrom存活的對(duì)象會(huì)被復(fù)制到此區(qū)域。ServiceFrom:一次Minor GC后Eden區(qū)或ServiceTo存活的對(duì)象會(huì)被復(fù)制到此區(qū)域。

ServiceTo和ServerFrom區(qū)本質(zhì)上沒(méi)什么區(qū)別,循環(huán)使用于存放GC后存活的對(duì)象。每次存活后對(duì)象的年齡加1,年齡到達(dá)15后依然存活的對(duì)象會(huì)被分配到老年代。 Minor GC一般采用復(fù)制算法。

1.2 老年代

用于存放大對(duì)象或者存活時(shí)間很長(zhǎng)的對(duì)象,占據(jù)堆內(nèi)存的2/3。老年代的對(duì)象比較穩(wěn)定,所以Major GC不會(huì)頻繁執(zhí)行。 進(jìn)入老年代的方式有三種:

對(duì)象存活時(shí)間長(zhǎng),默認(rèn)年齡為15。對(duì)象很大。動(dòng)態(tài)年齡判斷:按年齡從小到大將對(duì)象累加,如果加入某個(gè)年齡的對(duì)象后內(nèi)存超過(guò)一半,則從該年齡開(kāi)始,往上的年齡都進(jìn)入老年代。

在對(duì)象進(jìn)入老年代后,如果老年代空間不足,則會(huì)觸發(fā)Major GC。如果老年滿了裝不下了,則會(huì)OOM。 Major GC一般采用標(biāo)記清除或標(biāo)記整理算法。

1.3 永久代

Java8后永久代被移除,被元空間(Meta Space)取代。

元空間不是方法區(qū),而是方法區(qū)的一種實(shí)現(xiàn)。元空間并不使用JVM的內(nèi)存,而是使用操作系統(tǒng)的本地內(nèi)存。元空間主要用于存放Class信息以及元數(shù)據(jù)信息。元空間不會(huì)觸發(fā)GC。

2、如何對(duì)象是否存活

對(duì)象不存活就是垃圾。

引用計(jì)數(shù)法 一個(gè)對(duì)象,如果被引用則計(jì)數(shù)器加1,引用失效則計(jì)數(shù)器減1。 如果計(jì)數(shù)器值為0,則表示該對(duì)象不在被引用,可以進(jìn)行回收。 但有一個(gè)致命缺點(diǎn):無(wú)法處理循環(huán)依賴。導(dǎo)致沒(méi)有任何地方使用此方式。 可達(dá)性分析法 以根對(duì)象(GC root)為起點(diǎn),搜索被根對(duì)象集合所連接的目標(biāo)對(duì)象是否可達(dá)。 可作為GC Roots 的對(duì)象有: 1、虛擬機(jī)棧里的變量。 2、方法區(qū)中的靜態(tài)屬性引用的對(duì)象。 3、方法區(qū)中的常量引用的對(duì)象。 4、native方法引用的對(duì)象。

3、有哪些GC

MInor GC:新生代Eden區(qū)滿時(shí)觸發(fā)。Major GC:老年代內(nèi)存滿時(shí)觸發(fā)。Full GC:清除整個(gè)堆空間,通常和Major GC等價(jià)。

4、垃圾回收算法

4.1 標(biāo)記清除算法

概述:標(biāo)記無(wú)用對(duì)象,然后進(jìn)行清除回收。一共分為兩個(gè)階段:標(biāo)記階段和清除階段,所以該算法需要掃描兩次。優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,不需要對(duì)對(duì)象進(jìn)行移動(dòng)。缺點(diǎn):需要兩次掃描;會(huì)產(chǎn)生內(nèi)存碎片,提高了GC的頻率。使用:多用于老年代。

4.2 復(fù)制算法:

概述:將內(nèi)存劃為兩個(gè)相等的區(qū)域,每次只使用一個(gè)區(qū)域存放數(shù)據(jù)。垃圾回收時(shí),將存活對(duì)象復(fù)制到另一個(gè)區(qū)域,然后將當(dāng)前區(qū)域回收。優(yōu)點(diǎn):無(wú)內(nèi)存碎片;只掃描一次,效率高。缺點(diǎn):將可用內(nèi)存縮小為原來(lái)的一半,并且在對(duì)象存活率高的時(shí)候會(huì)頻繁進(jìn)行GC。使用:多用于新生代。

4.3 標(biāo)記整理算法

概述:在標(biāo)記可回收的對(duì)象后將所有存活的對(duì)象壓縮到內(nèi)存的一端,然后對(duì)端邊界以外的內(nèi)存進(jìn)行回收。需要兩次掃描。優(yōu)點(diǎn):不會(huì)存在內(nèi)存碎片。缺點(diǎn):需要兩次掃描,并且需要對(duì)對(duì)象進(jìn)行移動(dòng),效率偏低。使用:多用于老年代。

4.4 分代算法

對(duì)新生代中的對(duì)象采用復(fù)制算法,對(duì)老年代的對(duì)象采用標(biāo)記清除或標(biāo)記整理算法。

五、垃圾回收器

1、Serial + Serial Old

這是一組單線程垃圾回收器,并且GC線程在運(yùn)行時(shí)會(huì)STW。

2、Parallel Scavenge + Parallel Old

相比于Serial + Serial Old垃圾收集器,PS+PO的組合優(yōu)點(diǎn)在于可以通過(guò)多線程(默認(rèn)為CPU數(shù)量)進(jìn)行垃圾回收,但是PS+PO依然會(huì)STW。

3、ParNew + CMS

ParNew收集器就是PS收集器為了兼容CMS做了部分改進(jìn)產(chǎn)生的。 CMS 收集器是一種以最短回收停頓時(shí)間為目標(biāo)的收集器,以 “ 最短用戶線程停頓時(shí)間 ” 著稱。整個(gè)垃圾收集過(guò)程分為 4 個(gè)步驟:

初始標(biāo)記:標(biāo)記一下 GC Roots 能直接關(guān)聯(lián)到的對(duì)象,速度較快。會(huì)STW。并發(fā)標(biāo)記:標(biāo)記出全部的垃圾對(duì)象,并且此時(shí)用戶線程依然在運(yùn)行,所以會(huì)有新的垃圾產(chǎn)生。垃圾回收的絕大部分耗時(shí)都在此階段。重新標(biāo)記:修正并發(fā)標(biāo)記階段因用戶程序繼續(xù)運(yùn)行而導(dǎo)致垃圾對(duì)象的標(biāo)記記錄(可能不再是垃圾)。但并發(fā)標(biāo)記產(chǎn)生的新垃圾無(wú)法處理,即產(chǎn)生浮動(dòng)垃圾。會(huì)STW。并發(fā)清除:用標(biāo)記-清除算法清除垃圾對(duì)象(所以CMS會(huì)產(chǎn)生內(nèi)存碎片),可以和用戶線程并發(fā)執(zhí)行。

CMS收集器缺點(diǎn):

對(duì) CPU 資源敏感:默認(rèn)分配的垃圾收集線程數(shù)為(CPU 數(shù)+3)/4,隨著 CPU 數(shù)量下降,占用 CPU 資源越多,吞吐量越小。無(wú)法處理浮動(dòng)垃圾(Floating Garbage):由于存在浮動(dòng)垃圾,并且在并發(fā)標(biāo)記階段用戶線程也在并發(fā)執(zhí)行,CMS 收集器不能像其他收集器那樣等老年代被填滿時(shí)再進(jìn)行GC,需要預(yù)留一部分空間提供用戶線程運(yùn)行使用。當(dāng) CMS 運(yùn)行時(shí),預(yù)留的內(nèi)存空間無(wú)法滿足用戶線程的需要,就會(huì)出現(xiàn) “ Concurrent Mode Failure ”的錯(cuò)誤,這時(shí)將會(huì)啟動(dòng)后備預(yù)案,臨時(shí)用 Serial Old 來(lái)重新進(jìn)行老年代的垃圾收集。

4、G1垃圾收集器

在JDK1.9后,G1成為了默認(rèn)的垃圾回收器。并且G1垃圾回收期在邏輯上分代,物理上不分代。

G1的堆區(qū)在分代的基礎(chǔ)上,引入分區(qū)的概念:

G1將堆分成了若干Region,這些分區(qū)不要求是連續(xù)的內(nèi)存空間。Region的大小可以通過(guò)G1HeapRegionSize參數(shù)進(jìn)行設(shè)置,其必須是2的冪,范圍允許為1Mb到32Mb。JVM的會(huì)基于堆內(nèi)存的初始值和最大值的平均數(shù)計(jì)算分區(qū)的尺寸,平均的堆尺寸會(huì)分出約2000個(gè)Region。分區(qū)大小一旦設(shè)置,則啟動(dòng)之后不會(huì)再變化。分區(qū)可以有效利用內(nèi)存空間,因?yàn)槭占w是使用“標(biāo)記-整理”,Region之間基于“復(fù)制”算法,GC后會(huì)將存活對(duì)象復(fù)制到可用分區(qū)(未分配的分區(qū)),所以不會(huì)產(chǎn)生空間碎片。

G1收集器的運(yùn)作大致可以分為以下步驟:

初始標(biāo)記:標(biāo)記出 GC Roots 直接關(guān)聯(lián)的對(duì)象,并且修改TAMS(Next Top at Mark Set)的值,讓下一個(gè)階段用戶程序并發(fā)運(yùn)行時(shí),能在正確可用的Region中創(chuàng)建新對(duì)象,會(huì)STW。并發(fā)標(biāo)記:從GC Root 開(kāi)始對(duì)堆中的對(duì)象進(jìn)行可達(dá)性分析,找出存活對(duì)象。最終標(biāo)記:修正并發(fā)標(biāo)記階段因用戶程序繼續(xù)運(yùn)行而導(dǎo)致垃圾對(duì)象的標(biāo)記記錄(可能不再是垃圾),并且虛擬機(jī)將這段時(shí)間對(duì)象變化記錄在線程Remembered Set Logs里面,最終標(biāo)記需要把Remembered Set Logs的數(shù)據(jù)合并到Remembered Sets中,這個(gè)階段耗時(shí)較長(zhǎng),但可以和用戶線程并發(fā)執(zhí)行。會(huì)STW。篩選回收:篩選回收階段會(huì)對(duì)各個(gè) Region 的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的 GC 停頓時(shí)間來(lái)指定回收計(jì)劃(用最少的時(shí)間來(lái)回收包含垃圾最多的區(qū)域,這就是 Garbage First 的由來(lái)——第一時(shí)間清理垃圾最多的區(qū)塊),這里為了提高回收效率,并沒(méi)有采用和用戶線程并發(fā)執(zhí)行的方式,而是STW。

柚子快報(bào)激活碼778899分享:JVM基礎(chǔ)知識(shí)整理

http://yzkb.51969.com/

文章鏈接

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

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

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

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

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

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

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

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

文章目錄