成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java中什么是類加載?類加載的過程?

開發(fā) 前端
二進(jìn)制流可以來源于 class 文件,或通過字節(jié)碼工具生成的字節(jié)碼或來自于網(wǎng)絡(luò)。只要符合格式的二進(jìn)制流,JVM 來者不拒。

類加載指的是把類加載到 JVM 中。把二進(jìn)制流存儲到內(nèi)存中,之后經(jīng)過一番解析、處理轉(zhuǎn)化成可用的 class 類。

二進(jìn)制流可以來源于 class 文件,或通過字節(jié)碼工具生成的字節(jié)碼或來自于網(wǎng)絡(luò)。只要符合格式的二進(jìn)制流,JVM 來者不拒。

虛擬機(jī)遇到?條 new 指令時(shí),?先將去檢查這個(gè)指令的參數(shù)是否能在常量池中定位到這個(gè)類的符號引?,并且檢查這個(gè)符號引?代表的類是否已被加載過、解析和初始化過。如果沒有,那必須先執(zhí)?相應(yīng)的類加載過程。類加載過程包括了加載、連接、初始化三個(gè)階段,其中連接還可以分為驗(yàn)證、準(zhǔn)備、解析。

圖片圖片

加載

將二進(jìn)制流讀入內(nèi)存中,生成一個(gè) Class 對象。

在加載階段,虛擬機(jī)需要完成以下三件事情:

  • 通過一個(gè)類的全限定名來獲取其定義的二進(jìn)制字節(jié)流。
  • 將這個(gè)字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
  • 在Java堆中生成一個(gè)代表這個(gè)類的java.lang.Class對象,作為對方法區(qū)中這些數(shù)據(jù)的訪問入口。

圖片圖片

這個(gè)階段既可以使用系統(tǒng)提供的類加載器來完成加載,也可以自定義自己的類加載器來完成加載

驗(yàn)證

確保Class文件的字節(jié)流中包含的信息符合JVM規(guī)范,保證在運(yùn)行后不會危害虛擬機(jī)自身的安全。即安全性檢查,主要包括四種驗(yàn)證:

  • 文件格式驗(yàn)證: 驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范;例如: 是否以0xCAFEBABE開頭、主次版本號是否在當(dāng)前虛擬機(jī)的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型。
  • 元數(shù)據(jù)驗(yàn)證:: 對字節(jié)碼描述的信息進(jìn)行語義分析(注意: 對比javac編譯階段的語義分析),以保證其描述的信息符合Java語言規(guī)范的要求;例如: 這個(gè)類是否有父類,除了java.lang.Object之外。
  • 字節(jié)碼驗(yàn)證:通過數(shù)據(jù)流和控制流分析,確定程序語義是合法的、符合邏輯的。
  • 符號引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行

驗(yàn)證階段是非常重要的,但不是必須的,它對程序運(yùn)行期沒有影響,如果所引用的類經(jīng)過反復(fù)驗(yàn)證,那么可以考慮采用-Xverifynone參數(shù)來關(guān)閉大部分的類驗(yàn)證措施,以縮短虛擬機(jī)類加載的時(shí)間。

準(zhǔn)備

準(zhǔn)備階段是正式為static 變量分配內(nèi)存并設(shè)置類變量初始值的階段,這些內(nèi)存都將在方法區(qū)中分配。

static變量在分配空間和賦值是在兩個(gè)階段完成的。分配空間在準(zhǔn)備階段完成,賦值在初始化階段完成。也就是說這里給類變量設(shè)置初始值,設(shè)置的是數(shù)據(jù)類型默認(rèn)的零值(如0、0L、null、false等)。

  • 如果 static 變量是 ?nal 的基本類型,以及字符串常量,那么編譯階段值就確定了,賦值在準(zhǔn)備階段完成。
  • 如果 static 變量是 ?nal 的,但屬于引用類型,那么賦值會在初始化階段完成。

解析

將常量池內(nèi)的符號引用替換為直接引用的過程。符號引用用于描述目標(biāo),直接引用直接指向目標(biāo)的地址。

  • 未解析時(shí),常量池中的看到的對象僅是符號,未真正的存在于內(nèi)存中。
  • 解析以后,會將常量池中的符號引用解析為直接引用。

初始化

初始化階段會執(zhí)行cinit方法來為 類變量static變量 賦上定義的值并執(zhí)行類中的靜態(tài)代碼塊;這里的賦值才是代碼里面的賦值,準(zhǔn)備階段只是設(shè)置初始值占個(gè)坑。

在Java中對類變量進(jìn)行初始值設(shè)定有兩種方式:

  • 聲明類變量是指定初始值
  • 使用靜態(tài)代碼塊為類變量指定初始值

何時(shí)進(jìn)行類加載?

  • 定義了main的類,啟動(dòng)main方法時(shí)該類會被加載
  • 創(chuàng)建類的實(shí)例,即new對象的時(shí)候
  • 訪問類的靜態(tài)方法
  • 訪問類的靜態(tài)變量
  • 反射 Class.forName()

JVM初始化步驟?

  • 假如這個(gè)類還沒有被加載和連接,則程序先加載并連接該類
  • 假如該類的直接父類還沒有被初始化,則先初始化其直接父類
  • 假如類中有初始化語句,則系統(tǒng)依次執(zhí)行這些初始化語句

初始化發(fā)生的時(shí)機(jī)?

概括得說,類初始化是【懶惰的】,只有當(dāng)對類的主動(dòng)使用的時(shí)候才會導(dǎo)致類的初始化。

  • main 方法所在的類,總會被首先初始化
  • 首次訪問這個(gè)類的靜態(tài)變量或靜態(tài)方法時(shí)
  • 子類初始化,如果父類還沒初始化,會引發(fā)父類初始化
  • 子類訪問父類的靜態(tài)變量,只會觸發(fā)父類的初始化
  • Class.forName new 會導(dǎo)致初始化

不會導(dǎo)致類初始化的情況?

  • 訪問類的 static final 靜態(tài)常量(基本類型和字符串)不會觸發(fā)初始化。
  • 類對象.class 不會觸發(fā)初始化
  • 創(chuàng)建該類的數(shù)組不會觸發(fā)初始化
  • 類加載器的 loadClass 方法
  • Class.forName 的參數(shù) 2 為 false 時(shí)

cinit方法如果執(zhí)行失敗了怎么辦,這個(gè)類還能用嗎?

  • 在Java類加載的過程中,cinit 方法實(shí)際上指的是類的靜態(tài)初始化方法,也就是類的靜態(tài)代碼塊或者靜態(tài)變量的初始化代碼。如果類的靜態(tài)初始化方法執(zhí)行失敗,通常會導(dǎo)致類的初始化失敗,這意味著這個(gè)類不能被正常使用。會拋出異常,如 ExceptionInInitializerError
  • 在Java中,類的靜態(tài)初始化方法只會執(zhí)行一次,無論類被加載多少次,靜態(tài)初始化方法只會在首次加載類的時(shí)候執(zhí)行。因此,cinit 方法不會多次執(zhí)行。一旦類的靜態(tài)初始化方法執(zhí)行過,后續(xù)對同一個(gè)類的加載都不會再次觸發(fā)靜態(tài)初始化方法的執(zhí)行。這種機(jī)制確保了類的靜態(tài)初始化只會在需要的時(shí)候執(zhí)行一次,避免了不必要的開銷和重復(fù)操作。

分配內(nèi)存

在類加載后,接下來虛擬機(jī)將為新?對象分配內(nèi)存。

分配在哪?

主要就是根據(jù)JVM的分配機(jī)制:對象優(yōu)先分配Eden

  1. 先TLAB分配
  2. 再通過CAS在Eden區(qū)分配
  3. 大對象直接分配到老年代

TLAB:線程本地分配緩沖區(qū),為每?個(gè)線程預(yù)先在 Eden 區(qū)分配?塊?私有的緩存區(qū)域,JVM 在給線程中的對象分配內(nèi)存時(shí),?先在 TLAB 分配,當(dāng)對象?于 TLAB 中的剩余內(nèi)存或 TLAB 的內(nèi)存已?盡時(shí)(或者未開啟TLAB),再采?上述的 CAS 進(jìn)?內(nèi)存分配。默認(rèn)情況TLAB僅占每個(gè)Eden區(qū)域的1%。它的主要目的是在多線程并發(fā)環(huán)境下需要進(jìn)行內(nèi)存分配的時(shí)候,減少線程之間對于內(nèi)存分配區(qū)域的競爭,加速內(nèi)存分配的速度。

為什么要CAS分配內(nèi)存?

多個(gè)并發(fā)執(zhí)行的線程需要?jiǎng)?chuàng)建對象、申請分配內(nèi)存的時(shí)候,有可能在 Java 堆的同一個(gè)位置申請,這時(shí)就需要對擬分配的內(nèi)存區(qū)域進(jìn)行加鎖或者采用 CAS 等操作,保證這個(gè)區(qū)域只能分配給一個(gè)線程。

JVM對象分配內(nèi)存如何保證線程安全

在JVM中,為對象分配內(nèi)存的過程需要確保線程安全,因?yàn)樵诙嗑€程環(huán)境下,多個(gè)線程可能會同時(shí)嘗試創(chuàng)建對象。為了保證內(nèi)存分配的線程安全性,JVM采用了以下幾種機(jī)制和技術(shù):

  1. TLAB(Thread Local Allocation Buffer):

當(dāng)一個(gè)線程需要分配對象時(shí),首先會嘗試在TLAB中進(jìn)行分配。如果TLAB有足夠的空間,分配過程就是線程安全的,因?yàn)闆]有其他線程訪問這個(gè)內(nèi)存塊。

不足:當(dāng)TLAB空間不足時(shí),線程需要請求一個(gè)新的TLAB或者直接從共享堆中分配,這個(gè)過程需要一定的同步機(jī)制。

  1. CAS(Compare-And-Swap)機(jī)制:  當(dāng)TLAB耗盡或在涉及到跨線程的堆內(nèi)存分配時(shí),CAS有效避免了競爭條件。
  2. 分代收集:  雖然不是直接用于線程安全,但分代收集(年輕代、老年代、永久代/元空間)使得內(nèi)存管理更高效,減少了直接競爭的機(jī)會。

結(jié)合:TLAB一般對年輕代的內(nèi)存分配進(jìn)行優(yōu)化,更加局部化的內(nèi)存管理有助于線程安全。
通過運(yùn)用這些機(jī)制,JVM能夠在多線程環(huán)境下高效而安全地進(jìn)行內(nèi)存分配,并最大限度地減少同步操作帶來的性能損耗。這樣設(shè)計(jì)不僅提升了性能,也保證了對象內(nèi)存分配的安全性和一致性。

說說對象分配規(guī)則

在Java中,對象分配規(guī)則是關(guān)于如何為新對象分配內(nèi)存的一套規(guī)則,以確保內(nèi)存的有效使用和對象的正確初始化。以下是關(guān)于對象分配的主要規(guī)則:

  1. 內(nèi)存分配:新對象通常在堆內(nèi)存中分配內(nèi)存空間。
  2. 對象頭:在為對象分配內(nèi)存空間后,Java虛擬機(jī)會為對象分配一個(gè)對象頭。對象頭包含了一些關(guān)于對象的元信息,如對象的哈希碼、鎖狀態(tài)、垃圾回收信息等。
  3. 零值初始化:在對象內(nèi)存分配后,所有的成員變量會被初始化為零值。具體的零值取決于變量的數(shù)據(jù)類型。例如,整數(shù)類型會初始化為0,布爾類型會初始化為false,對象引用會初始化為null。
  4. 構(gòu)造函數(shù)調(diào)用:一旦對象內(nèi)存分配和零值初始化完成,Java虛擬機(jī)會調(diào)用對象的構(gòu)造函數(shù)。
  5. 對象引用:最后,new 關(guān)鍵字會返回對象的引用,將這個(gè)引用分配給一個(gè)變量,以便后續(xù)可以通過該變量訪問對象的屬性和方法。
  6. 垃圾回收管理:Java虛擬機(jī)會自動(dòng)管理對象的內(nèi)存。如果對象不再被引用,它會被標(biāo)記為垃圾,并在適當(dāng)?shù)臅r(shí)機(jī)由垃圾回收器回收,釋放占用的內(nèi)存。

圖片圖片

這些規(guī)則確保了對象在創(chuàng)建時(shí)的正確初始化和內(nèi)存管理。對于程序員來說,最重要的是編寫好構(gòu)造函數(shù)以確保對象在創(chuàng)建后具有合適的初始狀態(tài),并且不忘記在不再需要對象時(shí)將引用置為null,以便垃圾回收器能夠回收不再使用的對象。

何時(shí)進(jìn)行類卸載?

類的卸載條件很多,需要滿足以下三個(gè)條件,并且滿足了也不一定會被卸載:

  • 該類所有的實(shí)例都已經(jīng)被回收,也就是堆中不存在該類的任何實(shí)例。
  • 加載該類的 ClassLoader 已經(jīng)被回收。
  • 該類對應(yīng)的 Class 對象沒有在任何地方被引用,也就無法在任何地方通過反射訪問該類方法。

可以通過 -Xnoclassgc 參數(shù)來控制是否對類進(jìn)行卸載。

Java虛擬機(jī)將結(jié)束生命周期的幾種情況?(什么情況會導(dǎo)致JVM退出)

  • 正常程序終止:  當(dāng)程序執(zhí)行完main方法,包括所有非守護(hù)線程都終止時(shí),JVM將正常退出。
  • 調(diào)用System.exit(int status):  顯式調(diào)用System.exit()方法,以指定的狀態(tài)碼終止當(dāng)前運(yùn)行的Java虛擬機(jī)。
  • 未捕獲的異常或錯(cuò)誤:  如果某個(gè)線程拋出的異常沒有被捕獲,并且此異常傳播到了主線程,JVM可能會終止。
  • Runtime.halt(int)或崩潰:

直接調(diào)用Runtime.halt()會立即停止Java進(jìn)程,類似于突然終止程序而不調(diào)用任何鉤子。

JVM的致命錯(cuò)誤(如內(nèi)存訪問違規(guī))也可能導(dǎo)致崩潰并退出。

  • 外部命令強(qiáng)制關(guān)閉:  例如通過操作系統(tǒng)的任務(wù)管理器或者控制臺命令,如kill命令。或者操作系統(tǒng)出現(xiàn)錯(cuò)誤而導(dǎo)致Java虛擬機(jī)進(jìn)程終止
責(zé)任編輯:武曉燕 來源: SevenCoding
相關(guān)推薦

2019-12-09 15:08:30

JavaTomcatWeb

2012-11-06 10:19:18

Java自定義加載Java類

2024-06-24 14:52:50

Android類加載器

2023-12-06 12:11:43

類加載器雙親委派模型

2021-07-05 06:51:43

Java機(jī)制類加載器

2012-02-14 13:39:57

Java

2012-02-09 10:31:17

Java

2019-07-24 08:34:35

Java對象數(shù)據(jù)結(jié)構(gòu)

2024-03-08 08:26:25

類的加載Class文件Java

2021-05-08 09:02:19

Java加載器

2009-02-03 09:42:53

JAVA類JVM指令forName方法

2024-03-12 07:44:53

JVM雙親委托機(jī)制類加載器

2024-12-02 09:01:23

Java虛擬機(jī)內(nèi)存

2023-01-28 10:40:56

Java虛擬機(jī)代碼

2021-01-06 09:01:05

javaclass

2020-12-30 08:01:07

Java隔離加載

2021-01-29 06:06:12

JDK15類加載Java

2024-09-06 09:37:45

WebApp類加載器Web 應(yīng)用

2019-03-05 14:59:42

Java虛擬機(jī)加載類

2017-09-20 08:07:32

java加載機(jī)制
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 亚洲一区久久 | 欧美四虎 | 日韩亚洲一区二区 | 日日干日日射 | 国产高清视频在线 | 九久久| 欧美三区在线观看 | 99国产精品视频免费观看一公开 | 国产一区二区成人 | 国产精品乱码一二三区的特点 | 日韩欧美在线播放 | av网站免费看 | 午夜视频精品 | 99热精品在线 | 免费黄色的视频 | 99久久免费精品国产男女高不卡 | 久久久高清 | 黄色一级大片视频 | 亚洲一区二区视频在线播放 | 国产91亚洲精品一区二区三区 | 精品国产18久久久久久二百 | 九九亚洲| 日韩快播电影 | 国产一区二区免费 | 中文字幕日韩在线观看 | 国产一二三视频在线观看 | 亚洲三区在线观看 | 美女激情av | 日日天天| 精品一区在线看 | 欧美精品久久久 | 九色 在线 | 国产日韩中文字幕 | 黄色欧美在线 | 亚洲综合色视频在线观看 | 成人av一区二区三区 | 黄色在线免费观看视频网站 | 亚洲国产精品精华素 | 狠狠操av| 中文字幕一二三区 | 久草网站 |