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

阿里高頻面試題,熱部署了解嗎?

開發 前端
驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。

[[415464]]

本文轉載自微信公眾號「稀飯下雪」,作者帥氣的小飯飯。轉載本文請聯系稀飯下雪公眾號。

熟悉雙親委派模型嗎?

熟悉,這題我會。

機會來了,我八股文大神可是專門修煉過這個的。

我們為啥不能在Java工程中定義同名的String的Java文件?

(⊙o⊙)…

這.....

多線程加載類的時候為什么沒有線程問題?

臥槽 ....

首先,在講解這道題之前,先來劃重點

類加載時機與過程

類從被加載到虛擬機內存中開始,到卸載出內存為止,它的整個生命周期包括:加載(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸載(Unloading)7個階段。其中準備、驗證、解析3個部分統稱為連接(Linking)

加載、驗證、準備、初始化和卸載這5個階段的順序是確定的,類的加載過程必須按照這種順序按部就班地開始,而解析階段則不一定:它在某些情況下可以在初始化階段之后再開始,這是為了支持Java語言的運行時綁定(也稱為動態綁定或晚期綁定)

加載

在加載階段(可以參考java.lang.ClassLoader的loadClass()方法),虛擬機需要完成以下3件事情:

  1. 通過一個類的全限定名來獲取定義此類的二進制字節流(并沒有指明要從一個Class文件中獲取,可以從其他渠道,譬如:網絡、動態生成、數據庫等);
  2. 將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構;
  3. 在內存中生成一個代表這個類的java.lang.Class對象,作為方法區這個類的各種數據的訪問入口;

驗證

驗證是連接階段的第一步,這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。驗證階段大致會完成4個階段的檢驗動作:

  1. 文件格式驗證;
  2. 元數據驗證;
  3. 字節碼驗證;
  4. 符號引用驗證;

準備

準備階段是正式為類變量分配內存并設置類變量初始值的階段,這些變量所使用的內存都將在方法區中進行分配。這時候進行內存分配的僅包括類變量(被static修飾的變量),而不包括實例變量,實例變量將會在對象實例化時隨著對象一起分配在堆中。其次,這里所說的初始值「通常情況」下是數據類型的零值,

例如:public static int a = 1

這個時候變量a在準備階段過后的初始值為0,而不是1,因為這個時候尚未開始執行任何java方法,而把a賦值為1的指令是程序被編譯后,存放于類構造器()方法中,所以把a賦值為1的動作將在初始化階段才執行。

而當:public static final int a = 2

這種情況又不同了,當類字段的屬性是ConstantValue時,會在準備階段初始化為指定的值,所以標志位final之后,a的值再準備階段便被初始化為2,而不再是1 了。

劃重點:這里其實也好理解,final標志的常量意味著是不變的,那么在準備階段直接賦值了就可以了,沒必要多此一舉,先賦初始值,再在初始化的時候額外再做一次。

解析

解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程。解析動作主要針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調用點限定符7類符號引用進行。

初始化

在介紹初始化時,要先介紹兩個方法::

在編譯生成class文件時,會自動產生兩個方法,一個是類的初始化方法, 另一個是實例的初始化方法

<clinit>:在jvm第一次加載class文件時調用,包括靜態變量初始化語句和靜態塊的執行

<init>: 在實例創建出來的時候調用,包括調用new操作符;調用 Class 或 Java.lang.reflect.Constructor 對象的newInstance()方法;調用任何現有對象的clone()方法;通過 java.io.ObjectInputStream 類的getObject() 方法反序列化。

類初始化階段是類加載過程的最后一步,到了初始化階段,才真正開始執行類中定義的java程序代碼。在準備階段、變量已經被賦值過一次系統要求的初始值,而在初始化階段,則根據開發人員通過程序去初始化類變量和其他資源,或者說:初始化階段是執行類構造器()方法的過程.

()方法是由編譯器自動收集類中的所有類變量的賦值動作和靜態語句塊 static{} 中的語句合并產生的,編譯器收集的順序是由語句在源文件中出現的順序所決定的,靜態語句塊只能訪問到定義在靜態語句塊之前的變量,定義在它之后的變量,在前面的靜態語句塊可以賦值,但是不能訪問。

「總結一大波美女:其實也這個過程不用記,靠理解最好了,你想想看哦,你要把一個類加載到虛擬機,是不是要有一個加載的過程,這個過程就是將你的class對應的二進制字節流加載到虛擬機中,加載完虛擬機是不是要校驗下,規則的你給的東西有沒有毒?驗證完了,是不是要幫我們把一些類變量設置下初始值?設置完了還有一些對象標志啊什么的,是不是也要幫忙解析成直接引用,最后是不是還要走下我們類的初始化方法。」

雙親委派模型

所謂雙親委派是指每次收到類加載請求時,先將請求委派給父類加載器完成(所有加載請求最終會委派到頂層的Bootstrap ClassLoader加載器中),如果父類加載器無法完成這個加載(該加載器的「搜索范圍」中沒有找到對應的類),子類嘗試自己加載, 如果都沒加載到,則會拋出 ClassNotFoundException 異常, 看到這里其實就解釋了文章開頭提出的第一個問題,父加載器已經加載了JDK 中的 String.class 文件,所以我們不能定義同名的 String java 文件。

這么做的好處是什么?

因為這樣可以避免重復加載,當父親已經加載了該類的時候,就沒有必要 ClassLoader 再加載一次。考慮到安全因素,我們試想一下,如果不使用這種委托模式,那我們就可以隨時使用自定義的String來動態替代java核心api中定義的類型,這樣會存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因為String 已經在啟動時就被引導類加載器(Bootstrcp ClassLoader)加載,所以用戶自定義的ClassLoader永遠也無法加載一個自己寫的String,除非你改變 JDK 中 ClassLoader 搜索類的默認算法。

我們發現除了啟動類加載器(BootStrap ClassLoader),每個類都有其"父類"加載器,這種組合關系是通過組合模式來決定的,而不是繼承關系。

三種類加載器分別職責是啥?

  1. 「Bootstrap ClassLoader」:這個加載器不是一個Java類,而是由底層的c++實現,負責在虛擬機啟動時加載Jdk核心類庫(如:rt.jar、resources.jar、charsets.jar等)以及加載后兩個類加載器。這個ClassLoader完全是JVM自己控制的,需要加載哪個類,怎么加載都是由JVM自己控制,別人也訪問不到這個類
  2. 「Extension ClassLoader」:是一個普通的Java類,繼承自ClassLoader類,負責加載{JAVA_HOME}/jre/lib/ext/目錄下的所有jar包。
  3. 「App ClassLoader」:是Extension ClassLoader的子對象,負責加載應用程序classpath目錄下的所有jar和class文件。

通常用這兩種方式來動態加載一個 java 類,「Class.forName()」 與 「ClassLoader.loadClass()」 ,但是兩個方法之間也是有一些細微的差別,具體看上一篇文章:Object詳談

雙親委派模型源碼解析

來看看核心loadClass的方法

可以看到方法有同步塊(synchronized), 這樣就算多線程情況也不會出現重復加載的情況。

JAVA熱部署實現

什么是熱部署(hotswap)?

Java 類是通過 Java 虛擬機加載的,某個類的 class 文件在被 classloader 加載后,會生成對應的 Class 對象,之后就可以創建該類的實例,而熱部署是在不重啟 Java 虛擬機的這一前提下,自動偵測到 class 文件的變化,更新運行時 class 的行為。

而實際上,對于同一個全限定名的java類,只能被加載一次,而且無法被卸載。

那么竟然類無法被卸載,那么能不能把她媽給換了?也就是類加載器,答案是可以的,我們可以自定義類的加載器,并重寫ClassLoader的findClass方法,然后熱部署步驟就是:

  1. 銷毀自定義ClassLoader(被該加載器加載的class也會自動卸載);
  2. 更新class
  3. 使用新的ClassLoader去加載class

最終落地到實現,其實就是將ClassLoader給覆蓋掉,怎么覆蓋,重新new一個同樣的ClassLoader就可以了。

「總結一大波:我們雖然不能對被加載的class動手動腳,但是卻可以對ClassLoader動手腳,搞掉它,然后使用新的ClassLoader加載class就可以了。」

那么什么時候回收掉老的類呢?畢竟替換了,就存在新舊問題了,也就存在內存泄露問題了。

通常情況下,在JSP,OSGI及其他一些支持熱替換的庫,都是需要進行類的卸載回收的,否則類在替換后,老的類就沒用了但是還在內存中,就會造成內存泄漏。

類的卸載需要滿足以下三個條件:

  • 該類所有的實例都已經被GC,也就是JVM中不存在該Class的任何實例。
  • 加載該類的ClassLoader已經被GC。
  • 該類的java.lang.Class 對象沒有在任何地方被引用,如不能在任何地方通過反射訪問該類的方法。

所以在自定義類加載器時,就要注意這一點,如果你是希望其使用完成后就被卸載,那么就需要特別留意類加載器及類的作用域了。

原文鏈接:https://mp.weixin.qq.com/s/JT4Vh_tXzNAQdLSAosy2cQ

 

責任編輯:武曉燕 來源: 稀飯下雪
相關推薦

2021-02-23 12:43:39

Redis面試題緩存

2019-11-26 10:30:11

CSS前端面試題

2021-01-22 11:58:30

MySQL數據庫開發

2019-12-26 09:52:33

Redis集群線程

2021-11-02 10:10:38

面試元素語言

2015-07-13 09:45:32

阿里校招

2020-08-31 12:20:07

Python面試題代碼

2022-08-22 18:57:29

React前端面試

2021-12-08 11:18:21

Spring Bean面試題生命周期

2022-04-15 09:23:29

Kubernetes面試題

2020-03-03 17:47:07

UDP TCP面試題

2018-01-02 09:23:38

數據分析算法阿里巴巴

2018-12-03 09:42:32

Java程序員阿里面試

2020-06-04 14:40:40

面試題Vue前端

2011-03-24 13:27:37

SQL

2023-11-13 07:37:36

JS面試題線程

2021-02-26 05:22:50

CPU接口網絡包

2021-09-07 18:40:55

單向數據流數據

2023-10-20 15:58:27

Python刪除指定字符

2025-03-20 07:54:57

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区在线不卡 | 国产精品精品视频一区二区三区 | 国产高清免费 | 狠狠入ady亚洲精品经典电影 | 国产 日韩 欧美 在线 | 欧美精品国产一区二区 | 蜜桃视频在线观看免费视频网站www | 99亚洲精品 | 在线一区二区三区 | 欧美日韩综合一区 | 欧美一区二区小视频 | 欧美精品乱码99久久影院 | 日韩精品 电影一区 亚洲 | 精品中文字幕视频 | av网址在线播放 | 一区二区不卡视频 | 日韩不卡三区 | 国产情品| 毛片的网址 | 亚洲一区中文字幕在线观看 | 天天狠狠 | 欧美一级一区 | 久久99国产精品久久99果冻传媒 | 日韩视频一区 | 51ⅴ精品国产91久久久久久 | 黑人巨大精品欧美一区二区免费 | 欧美久久久久久久久 | 中文字幕免费 | 91精品久久久久久久久99蜜臂 | 欧美激情综合色综合啪啪五月 | 日本免费黄色 | 国产日韩欧美一区二区 | 亚洲福利精品 | www.青娱乐 | 亚洲一区二区视频在线观看 | 久久精品99久久 | 黄网站在线播放 | 久久青青 | 久久久久免费精品国产 | 欧美日韩手机在线观看 | 国产一区二区三区四区三区四 |