国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

說說 JVM 的類加載機制『非專業』

云計算 虛擬化
類是在運行期間第一次使用時動態加載的,而不是一次性加載所有類。因為如果一次性加載,那么會占用很多的內存。

[[396813]]

類加載機制

類是在運行期間第一次使用時動態加載的,而不是一次性加載所有類。因為如果一次性加載,那么會占用很多的內存。

類的生命周期

包括以下 7 個階段:

  • 「加載(Loading)」
  • 「驗證(Verification)」
  • 「準備(Preparation)」
  • 「解析(Resolution)」
  • 「初始化(Initialization)」
  • 使用(Using)
  • 卸載(Unloading)

類加載過程 --- new 一個對象的過程

包含加載、驗證、準備、解析和初始化這 5 個階段。

1.加載

加載過程完成以下三件事:

其中二進制字節流可以從以下方式中獲取:

  • 從 ZIP 包讀取,成為 JAR、EAR、WAR 格式的基礎。
  • 從網絡中獲取,最典型的應用是 Applet。
  • 運行時計算生成,例如動態代理技術,在 java.lang.reflect.Proxy 使用 ProxyGenerator.generateProxyClass 的代理類的二進制字節流。
  • 由其他文件生成,例如由 JSP 文件生成對應的 Class 類。
  • 通過類的完全限定名稱獲取定義該類的二進制字節流。
  • 將該字節流表示的靜態存儲結構轉換為方法區的運行時存儲結構。
  • 在內存中生成一個代表該類的 Class 對象,作為方法區中該類各種數據的訪問入口。

2.驗證

格式驗證:驗證是否符合class文件規范 語義驗證:檢查一個被標記為final的類型是否包含子類;檢查一個類中的final方法是否被子類進行重寫;確保父類和子類之間沒有不兼容的一些方法聲明(比如方法簽名相同,但方法的返回值不同) 操作驗證:在操作數棧中的數據必須進行正確的操作,對常量池中的各種符號引用執行驗證(通常在解析階段執行,檢查是否可以通過符號引用中描述的全限定名定位到指定類型上,以及類成員信息的訪問修飾符是否允許訪問等)

3.準備

類變量是被 static 修飾的變量,準備階段為類變量分配內存并設置初始值,使用的是方法區的內存。

  1. public static int value = 123; 

如果類變量是常量,那么它將初始化為表達式所定義的值而不是 0。例如下面的常量 value 被初始化為 123 而不是 0。

  1. public static final int value = 123; 

實例變量不會在這階段分配內存,它會在對象實例化時隨著對象一起被分配在堆中。

4.解析

將常量池中的符號引用轉為直接引用(得到類或者字段、方法在內存中的指針或者偏移量,以便直接調用該方法),這個可以在初始化之后再執行,可以支持 Java 的動態綁定。

以上2、3、4三個階段又合稱為鏈接階段,鏈接階段要做的是將加載到JVM中的二進制字節流的類數據信息合并到JVM的運行時狀態中。

5.初始化

初始化階段是虛擬機執行類構造器 () 方法的過程,是真正開始執行類中定義的 Java 程序代碼。在前面的準備階段,類變量已經賦過一次系統要求的初始值,而在初始化階段,主要根據程序員通過程序制定的主觀計劃去初始化類變量和其它資源。

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

虛擬機會保證一個類的 () 方法在多線程環境下被正確的加鎖和同步,如果多個線程同時初始化一個類,只會有一個線程執行這個類的\ () 方法,其它線程都會阻塞等待,直到活動線程執行\ () 方法完畢。如果在一個類的 () 方法中有耗時的操作,就可能造成多個線程阻塞,在實際過程中此種阻塞很隱蔽。

上述步驟簡單來說就是分為以下兩步:

  • 類變量的賦值操作
  • 執行static代碼塊。static代碼塊只有jvm能夠調用。如果是多線程需要同時初始化一個類,僅僅只能允許其中一個線程對其執行初始化操作,其余線程必須等待,只有在活動線程執行完對類的初始化操作之后,才會通知正在等待的其他線程。

最終,方法區會存儲當前類的類信息,包括類的靜態變量、類初始化代碼(定義靜態變量時的賦值語句和靜態初始化代碼塊)、實例變量定義、實例初始化代碼(定義實例變量時的賦值語句實例代碼塊和構造方法)和實例方法,還有父類的類信息引用。

創建對象

假設是第一次使用一個類的話,那么需要經過上述的類加載的過程,之后才是創建對象。

「1、在堆區分配對象需要的內存」

分配的內存包括本類和父類的所有實例變量,但不包括任何靜態變量

「2、對所有實例變量賦默認值」

將方法區內對實例變量的定義拷貝一份到堆區,然后賦默認值

「3、執行實例初始化代碼」

初始化順序是先初始化父類再初始化子類,初始化時先執行實例代碼塊然后是構造方法。(第一執行類中的靜態代碼,包括靜態成 員變量的初始化和靜態語句塊的執行;第二執行類中的非靜態代碼,包括非靜態成員變量的初始化和非靜態語句塊的執行,最后執 行構造函數。在繼承的情況下,會首先執行父類的靜態代碼,然后執行子類的靜態代碼;之后執行父類的非靜態代碼和構造函數; 最后執行子類的非靜態代碼和構造函數)

「4、如果有類似于Child c = new Child()形式的c引用的話,在棧區定義Child類型引用變量c,然后將堆區對象的地址賦值給它」

需要注意的是,「每個子類對象持有父類對象的引用」,可在內部通過super關鍵字來調用父類對象,但在外部不可訪問。

存在繼承的情況下,初始化順序為:

  • 父類(靜態變量、靜態語句塊)
  • 子類(靜態變量、靜態語句塊)
  • 父類(實例變量、普通語句塊)
  • 父類(構造函數)
  • 子類(實例變量、普通語句塊)
  • 子類(構造函數)

類初始化的情況

主動引用

虛擬機規范中并沒有強制約束何時進行加載,但是規范嚴格規定了有且只有下列五種情況必須對類進行初始化(加載、驗證、準備都會隨之發生):

  • 遇到 new、getstatic、putstatic、invokestatic 這四條字節碼指令時,如果類沒有進行過初始化,則必須先觸發其初始化。最常見的生成這 4 條指令的場景是:使用 new 關鍵字實例化對象的時候;讀取或設置一個類的靜態字段(被 final 修飾、已在編譯期把結果放入常量池的靜態字段除外)的時候;以及調用一個類的靜態方法的時候。
  • 使用 java.lang.reflect 包的方法對類進行反射調用的時候,如果類沒有進行初始化,則需要先觸發其初始化。
  • 當初始化一個類的時候,如果發現其父類還沒有進行過初始化,則需要先觸發其父類的初始化。
  • 當虛擬機啟動時,用戶需要指定一個要執行的主類(包含 main() 方法的那個類),虛擬機會先初始化這個主類。

被動引用

以上的行為稱為對一個類進行主動引用。除此之外,所有引用類的方式都不會觸發初始化,稱為被動引用。被動引用的常見例子包括:

  • 通過子類引用父類的靜態字段,不會導致子類初始化。
  1. System.out.println(SubClass.value); // value 字段在 SuperClass 中定義 

通過數組定義來引用類,不會觸發此類的初始化。該過程會對數組類進行初始化,數組類是一個由虛擬機自動生成的、直接繼承自 Object 的子類,其中包含了數組的屬性和方法。

  1. SuperClass[] sca = new SuperClass[10]; 
  • 常量在編譯階段會存入調用類的常量池中,本質上并沒有直接引用到定義常量的類,因此不會觸發定義常量的類的初始化。
  1. System.out.println(ConstClass.HELLOWORLD); 

類與類加載器

兩個類相等,需要類本身相等,并且使用同一個類加載器進行加載。這是因為每一個類加載器都擁有一個獨立的類名稱空間。那么最終的相等包括了類的 Class 對象的 equals() 方法、isAssignableFrom() 方法、isInstance() 方法的返回結果為 true,也包括使用 instanceof 關鍵字做對象所屬關系判定結果為 true。

從 Java 虛擬機的角度來講,只存在以下兩種不同的類加載器:

  • 啟動類加載器(Bootstrap ClassLoader),使用 C++ 實現,是虛擬機自身的一部分;
  • 所有其它類的加載器,使用 Java 實現,獨立于虛擬機,繼承自抽象類 java.lang.ClassLoader。

那么上述又可以分為以下三種類加載器:BootstrapClassLoader、ExtensionClassLoader、App ClassLoader

  • 啟動類加載器(BootstrapClassLoader)是嵌在JVM內核中的加載器,該加載器是用C++語言寫的,主要負載加載JAVA_HOME/lib下的類庫,或者被 -Xbootclasspath 參數所指定的路徑中的,并且是虛擬機識別的(僅按照文件名識別,如 rt.jar,名字不符合的類庫即使放在 lib 目錄中也不會被加載)。

啟動類加載器無法被 Java 程序直接引用,用戶在編寫自定義類加載器時,如果需要把加載請求委派給啟動類加載器,直接使用 null 代替即可。

  • 擴展類加載器(ExtensionClassLoader)是用JAVA編寫,由 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)實現的。它負責將 /lib/ext 或者被 java.ext.dir 系統變量所指定路徑中的所有類庫加載到內存中,開發者可以直接使用擴展類加載器。

它的父類加載器是Bootstrap。

  • 應用程序類加載器(Application ClassLoader)這個類加載器是由 AppClassLoader(sun.misc.Launcher$AppClassLoader)實現的。一般負責加載應用程序classpath目錄下的所有jar和class文件。

開發者可以直接使用這個類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

它的父加載器為ExteClassLoader。

雙親委派模型

應用程序是由三種類加載器互相配合從而實現類加載,除此之外還可以加入自己定義的類加載器。下圖展示了類加載器之間的層次關系,稱為雙親委派模型(Parents Delegation Model)。這里的父子關系一般通過委托來實現,而不是繼承關系(Inheritance)。

  • 工作流程

如果一個類加載器收到了一個類加載請求,它不會自己去嘗試加載這個類,而是把這個請求轉交給父類加載器去完成。每一個層次的類加載器都是如此。因此所有的類加載請求都應該傳遞到最頂層的啟動類加載器中,只有到父類加載器反饋自己無法完成這個加載請求(在它的搜索范圍沒有找到這個類)時,子類加載器才會嘗試自己去加載。

  • 好處

使得 Java 類隨著它的類加載器一起具有一種帶有優先級的層次關系,從而使得基礎類得到統一。

例如 java.lang.Object 存放在 rt.jar 中,如果編寫另外一個 java.lang.Object 并放到 ClassPath 中,程序可以編譯通過。由于雙親委派模型的存在,所以在 rt.jar 中的 Object 比在 ClassPath 中的 Object 優先級更高,這是因為 rt.jar 中的 Object 使用的是啟動類加載器,而 ClassPath 中的 Object 使用的是應用程序類加載器。rt.jar 中的 Object 優先級更高,那么程序中所有的 Object 都是這個 Object。

  • demo

以下是抽象類 java.lang.ClassLoader 的代碼片段,其中的 loadClass() 方法運行過程如下:先檢查類是否已經加載過,如果沒有則讓父類加載器去加載。當父類加載器加載失敗時拋出 ClassNotFoundException,此時嘗試自己去加載。

  1. public abstract class ClassLoader { 
  2.     // The parent class loader for delegation 
  3.     private final ClassLoader parent; 
  4.  
  5.     public Class<?> loadClass(String name) throws ClassNotFoundException { 
  6.         return loadClass(namefalse); 
  7.     } 
  8.  
  9.     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 
  10.         synchronized (getClassLoadingLock(name)) { 
  11.             // Firstcheck if the class has already been loaded 
  12.             Class<?> c = findLoadedClass(name); 
  13.             if (c == null) { 
  14.                 try { 
  15.                     if (parent != null) { 
  16.                         c = parent.loadClass(namefalse); 
  17.                     } else { 
  18.                         c = findBootstrapClassOrNull(name); 
  19.                     } 
  20.                 } catch (ClassNotFoundException e) { 
  21.                     // ClassNotFoundException thrown if class not found 
  22.                     // from the non-null parent class loader 
  23.                 } 
  24.  
  25.                 if (c == null) { 
  26.                     // If still not found, then invoke findClass in order 
  27.                     // to find the class. 
  28.                     c = findClass(name); 
  29.                 } 
  30.             } 
  31.             if (resolve) { 
  32.                 resolveClass(c); 
  33.             } 
  34.             return c; 
  35.         } 
  36.     } 
  37.  
  38.     protected Class<?> findClass(String name) throws ClassNotFoundException { 
  39.         throw new ClassNotFoundException(name); 
  40.     } 
  • 自定義類加載器實現

以下代碼中的 FileSystemClassLoader 是自定義類加載器,繼承自 java.lang.ClassLoader,用于加載文件系統上的類。它首先根據類的全名在文件系統上查找類的字節代碼文件(.class 文件),然后讀取該文件內容,最后通過 defineClass() 方法來把這些字節代碼轉換成 java.lang.Class 類的實例。

java.lang.ClassLoader 的 loadClass() 實現了雙親委派模型的邏輯,自定義類加載器一般不去重寫它,但是需要重寫 findClass() 方法。

  1. public class FileSystemClassLoader extends ClassLoader { 
  2.  
  3.     private String rootDir; 
  4.  
  5.     public FileSystemClassLoader(String rootDir) { 
  6.         this.rootDir = rootDir; 
  7.     } 
  8.  
  9.     protected Class<?> findClass(String name) throws ClassNotFoundException { 
  10.         byte[] classData = getClassData(name); 
  11.         if (classData == null) { 
  12.             throw new ClassNotFoundException(); 
  13.         } else { 
  14.             return defineClass(name, classData, 0, classData.length); 
  15.         } 
  16.     } 
  17.  
  18.     private byte[] getClassData(String className) { 
  19.         String path = classNameToPath(className); 
  20.         try { 
  21.             InputStream ins = new FileInputStream(path); 
  22.             ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
  23.             int bufferSize = 4096; 
  24.             byte[] buffer = new byte[bufferSize]; 
  25.             int bytesNumRead; 
  26.             while ((bytesNumRead = ins.read(buffer)) != -1) { 
  27.                 baos.write(buffer, 0, bytesNumRead); 
  28.             } 
  29.             return baos.toByteArray(); 
  30.         } catch (IOException e) { 
  31.             e.printStackTrace(); 
  32.         } 
  33.         return null
  34.     } 
  35.  
  36.     private String classNameToPath(String className) { 
  37.         return rootDir + File.separatorChar 
  38.                 + className.replace('.', File.separatorChar) + ".class"
  39.     } 

巨人的肩膀

程序鍋春招筆記的摘記

https://github.com/CyC2018/CS-Notes

本文轉載自微信公眾號「多選參數」,可以通過以下二維碼關注。轉載本文請聯系多選參數公眾號。

 

責任編輯:武曉燕 來源: 多選參數
相關推薦

2021-05-12 20:37:56

JVM 內存管理

2023-10-31 16:00:51

類加載機制Java

2017-09-20 08:07:32

java加載機制

2017-03-08 10:30:43

JVMJava加載機制

2023-08-02 08:38:27

JVM加載機制

2024-12-02 09:01:23

Java虛擬機內存

2024-03-12 07:44:53

JVM雙親委托機制類加載器

2022-10-08 08:34:34

JVM加載機制代碼

2020-05-20 22:13:26

JVM加載機制虛擬機

2021-09-24 08:10:40

Java 語言 Java 基礎

2020-10-26 11:20:04

jvm類加載Java

2019-12-30 11:25:06

Jvm運行java

2024-03-08 08:26:25

類的加載Class文件Java

2024-09-06 09:37:45

WebApp類加載器Web 應用

2024-02-20 08:13:35

類加載引用Class

2021-01-06 09:01:05

javaclass

2021-06-16 00:57:16

JVM加載機制

2021-07-05 06:51:43

Java機制類加載器

2024-12-04 09:01:55

引導類加載器C++

2021-02-28 11:58:33

JVM機制語言
點贊
收藏

51CTO技術棧公眾號

欧美一级搡bbbb搡bbbb| 国产精品永久免费观看| 久久偷看各类wc女厕嘘嘘偷窃| 天堂中文字幕在线| 精品国产乱子伦一区二区| 91在线观看免费视频| 久久精品国产欧美激情| 日本精品福利视频| 日韩美香港a一级毛片| 国产色一区二区| 亚洲激情在线观看视频免费| 毛片av在线播放| 深夜福利一区| 一区二区在线观看av| 亚洲精品免费网站| 黄色大片在线看| 午夜精品福利影院| 午夜精品影院在线观看| 欧美激情第一页在线观看| 第一av在线| 卡通动漫精品一区二区三区| 亚洲国产一区二区三区在线播放| 色偷偷久久人人79超碰人人澡| 国产一区二区精品在线| 国产理论在线| 国产精品毛片无遮挡高清| 国产在线98福利播放视频| 韩国福利在线| 国产一区二区视频在线| 亚洲精品永久免费精品| 人妻激情另类乱人伦人妻 | 中文国产亚洲喷潮| 99热在线免费| 国内精品久久久久久久97牛牛| 日韩高清不卡av| 日本三区在线观看| 亚洲国产一区二区三区在线播放| 精品久久久影院| 日本www高清视频| 亚洲高清av| 综合激情国产一区| 国产真实乱子伦| 久久国产66| 欧美在线www| 污香蕉视频在线观看| 韩国三级电影一区二区| 国产精品露脸av在线| 中文字幕在线影院| 99久久婷婷国产综合精品电影| 99re视频在线| 免费观看性欧美大片无片| 91麻豆精品国产自产在线| 久久婷婷综合色| 久久一区二区三区超碰国产精品| 国外成人在线播放| cao在线视频| 色哟哟一区二区| 亚洲一级免费观看| 麻豆91在线看| 999热视频| 成人软件在线观看| 欧美一区二区三区婷婷月色| 亚洲一区三区在线观看| 欧美丰满老妇| 欧美激情欧美狂野欧美精品| 黄网站在线播放| 午夜精品成人在线视频| 在线视频福利一区| 免费日韩av片| 91观看网站| 韩国中文字幕2020精品| 久久国产免费看| 国产在线日韩在线| 成人香蕉社区| 精品久久久久久最新网址| 白白色在线发布| 国产69精品久久99不卡| 精品中文字幕人| 精品国产欧美| 久久视频免费观看| 高清av不卡| 亚洲欧美另类在线观看| 亚洲区欧洲区| 7777女厕盗摄久久久| bt在线麻豆视频| 日本道免费精品一区二区三区| 国产精品三级a三级三级午夜| 国产成a人亚洲| 青青青国产在线观看| 91伊人久久大香线蕉| 国产美女在线一区| av福利精品导航| 99999精品视频| 国产午夜亚洲精品午夜鲁丝片| 亚洲天堂av线| 亚洲一区二区三区爽爽爽爽爽| ga∨成人网| 欧美午夜精品一区二区三区| 日韩大片在线永久免费观看网站| 五月激情综合婷婷| 人操人视频在线观看| 欧美久久久久免费| 亚洲天堂资源| 欧美国产日韩一区二区三区| 日韩成人一区| 日本久久久久久久久| 亚洲精品电影| 欧美18视频| 国产成人福利片| 日本a级片免费| 日韩欧美国产网站| 麻豆tv在线| 国产一区二区三区网站| 国精产品一区一区三区mba下载| 色综合天天视频在线观看 | 精品众筹模特私拍视频| 亚洲色图在线观看| 国产亚洲精品美女久久| 日韩美女视频中文字幕| 三上亚洲一区二区| 一区二区精品视频| 国产精品第一页第二页第三页| 最近97中文超碰在线| 亚洲国产精品福利| crdy在线观看欧美| 日韩精品在线一区二区| 大地资源中文在线观看免费版| 亚洲а∨天堂久久精品9966| 欧美精品日韩少妇| xx视频.9999.com| 91精品国产视频| 无码av天堂一区二区三区| 亚洲精品一二三| 国产伦理精品| 国产精品久久久久91| 欧美精品三区| 中文字幕中文字幕一区三区| 中文字幕 久热精品 视频在线| 亚洲成人av免费看| 精品国产制服丝袜高跟| av2020不卡| 成人黄色生活片| 国产午夜亚洲精品理论片色戒| 青青草免费观看免费视频在线| 国产小视频国产精品| 国内精品久久久久久久97牛牛 | 99热这里只有精品8| 国产福利一区视频| 日韩精品一区二区三区在线观看| 色先锋久久影院av| av久久久久久| 日韩一级黄色片| av永久不卡| 区一区二区三区中文字幕| 国产精品一区二区在线播放| 天堂电影在线| 久久久久久久久久久久av| 日韩国产在线一| 在线国产中文字幕| 亚洲图片在线综合| 久久国产精品区| 美州a亚洲一视本频v色道| 一区二区三区视频免费| 亚洲无线一线二线三线区别av| 99热免费在线| 久久成人免费视频| 免费成人在线视频观看| 青青九九免费视频在线| 青青久久aⅴ北条麻妃| 国产欧美一区二区精品仙草咪| 免费日韩电影| 国产精品无码乱伦| 91精品国产入口| 99视频精品| 午夜不卡视频| 国产一区二区在线观看免费播放| 久久久噜噜噜久久人人看| 国产成人艳妇aa视频在线 | 天天色 色综合| 成人福利一区| 国精产品一区一区三区视频| 亚洲va韩国va欧美va| 亚洲精品蜜桃乱晃| 黄色录像1级片| 中文字幕亚洲一区二区三区五十路 | 性欧美xxx69hd高清| 亚洲欧洲在线一区| 欧美另类久久久品| 亚洲成人资源| 污污的网站在线看| 中文字幕剧情在线观看一区| 亚洲激情视频网| 成人午夜精品一区二区三区| 成人私拍视频| 欧美xxxx吸乳| 一本色道久久综合狠狠躁篇怎么玩 | 久久久三级国产网站| 国产日韩三级| 深夜福利在线观看直播| 国产成人中文字幕|