深入理解Java虛擬機:Java類的加載機制

本篇內容包括:Java 類的加載機制(Jvm 結構組成、Java 類的加載)、類的生命周期(加載-驗證-準備-解析-初始化-使用-卸載)、類加載器 以及 雙親委派模型。

一、Java 類的加載機制

1、 Jvm 結構組成

Jvm 整體組成可分為四個部分:類加載器、運行時數據區(Runtime Data Area)、執行引擎(Execution Engine)、本地庫接口(Native Interface)

  • 類加載器:負責從字節碼(Class)文件中,加載 class 信息到運行時數據區的方法區;
  • 運行時數據區:存放 Jvm 在執行 Java 程序時相關數據的區域;
  • 執行引擎:將字節碼翻譯成底層系統指令再交由 CPU 去執行;
  • 本地庫接口:執行過程中可能需要調用到其他語言(比如 C 語言)的本地接口。

PS:Javac 是收錄于 Jdk 中的 Java 語言編譯器。該工具可以將后綴名為 .java 的源文件編譯為后綴名為 .class 的可以運行于 Java 虛擬機的字節碼。

程序在被執行之前, Java 代碼會被先轉換成字節碼(.class 文件), Jvm 首先通過一定的方式類加載器(ClassLoader)把字節碼文件加載到內存中運行時數據區(Runtime Data Area),而字節碼文件是 Jvm 提供的一套指令集規范,并不能直接交個底層操作系統去執行,因此需要特定的命令解析器執行引擎(Execution Engine)將字節碼翻譯成底層系統指令再交由 CPU 去執行,而這個過程中需要調用其他語言的接口本地庫接口(Native Interface)來實現整個程序的功能,這就是這 4 個主要組成部分的職責與功能。

而我們通常所說的 Jvm 組成指的是運行時數據區,因為通常需要程序員調試分析的區域就是運行時數據區,或者更具體的來說就是運行時數據區里面的堆(Heap)模塊!

2、Java 類的加載

類的加載指的是將類的 .class 文件中的二進制數據讀入到內存中,將其放在運行時數據區的方法區內,然后在堆區創建一個 java.lang.Class 對象,用來封裝類在方法區內的數據結構。類的加載的最終產品是位于堆區中的 Class 對象,Class 對象封裝了類在方法區內的數據結構,并且向 Java 程序員提供了訪問方法區內的數據結構的接口。

類加載器并不需要等到某個類被首次主動使用時再加載它, Jvm 規范允許類加載器在預料某個類將要被使用時就預先加載它,如果在預先加載的過程中遇到了 .class 文件缺失或存在錯誤,類加載器必須在程序首次主動使用該類時才報告錯誤( LinkageError 錯誤)如果這個類一直沒有被程序主動使用,那么類加載器就不會報告錯誤。

加載.class 文件的方式:

  • 從本地系統中直接加載
  • 通過網絡下載 .class 文件
  • 從 zip、jar 等歸檔文件中加載 .class 文件
  • 從專有數據庫中提取 .class 文件
  • 將 Java 源文件動態編譯為 .class 文件
  • 由其他文件生成

二、Java 類的生命周期

類從被加載到 Jvm 內存中開始到卸載出內存為止,生命周期分為7個階段:加載-驗證-準備-解析-初始化-使用-卸載。(或分為5個階段,把 驗證-準備-解析 分為連接階段)

1、加載

加載過程就是把 class 字節碼文件載入到虛擬機中,至于從哪兒加載,虛擬機設計者并沒有限定,你可以從文件、壓縮包、網絡、數據庫等等地方加載 class 字節碼。

  • 通過一個類的全限定名來獲取其定義的二進制字節流;
  • 將這個字節流所代表的靜態存儲結構轉化為方法區的運行時數據結構;
  • 在Java堆中生成一個代表這個類的 java.lang.Class 對象,作為對方法區中這些數據的訪問入口

2、驗證(連接階段的第一步):確保被加載的類的正確性

這一階段的目的是為了確保Class文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。驗證階段大致會完成4個階段的檢驗動作:文件格式驗證、元數據驗證、字節碼驗證、符號引用驗證

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

3、準備(連接階段的第二步):為類的靜態變量分配內存,并將其初始化為默認值

準備階段的工作就是為類的靜態變量分配內存并設為 Jvm 默認的初值,對于非靜態的變量,則不會為它們分配內存。靜態變量的初值為 Jvm 默認的初值,而不是我們在程序中設定的初值。(僅包含類變,不包含實例變量)

4、解析(連接階段的第三步):把類中的符號引用轉換為直接引用

解析階段是虛擬機將常量池內的符號引用替換為直接引用的過程,解析動作主要針對類或接口、字段、類方法、接口方法、方法類型、方法句柄和調用點限定符7類符號引用進行。符號引用就是一組符號來描述目標,可以是任何字面量。

直接引用就是直接指向目標的指針、相對偏移量或一個間接定位到目標的句柄。

5、初始化:為類的靜態變量賦予正確的初始值

主要對類變量進行初始化。在Java中對類變量進行初始值設定有兩種方式:

  1. 聲明類變量是指定初始值;
  2. 使用靜態代碼塊為類變量指定初始值

Jvm初始化步驟:

  1. 假如這個類還沒有被加載和連接,則程序先加載并連接該類

  2. 假如該類的直接父類還沒有被初始化,則先初始化其直接父類

  3. 假如類中有初始化語句,則系統依次執行這些初始化語句

類初始化時機:只有當對類的主動使用的時候才會導致類的初始化,類的主動使用包括以下六種:

  1. 創建類的實例,也就是new的方式
  2. 訪問某個類或接口的靜態變量,或者對該靜態變量賦值
  3. 調用類的靜態方法
  4. 反射(如 Class.forName(“com.shengsiyuan.Test”) )
  5. 初始化某個類的子類,則其父類也會被初始化
  6. Java虛擬機啟動時被標明為啟動類的類( JavaTest ),直接使用 java.exe 命令來運行某個主類

三、類加載器

類加載器是負責將可能是網絡上、也可能是磁盤上的 .class 文件加載到內存中。并為其生成對應的 java.lang.Class 對象。一旦一個類被載入 Jvm 了,同一個類就不會被再次加載。那么怎樣才算是同一個類?在 Java 中一個類用其全限定類名(包名和類名)作為其唯一標識,但是在 Jvm 中,一個類用其全限定類名和其類加載器作為其唯一標識。也就是說,在 Java 中的同一個類,如果用不同的類加載器加載,則生成的 .class 對象認為是不同的。

當 Jvm啟動時,會形成由三個類加載器組成的初始類加載器層次結構:

  • 啟動類加載器(Bootstrap ClassLoader):是嵌在 Jvm 內核中的加載器,該加載器是用 C++ 語言寫的,主要負載加載 JAVA_HOME/lib 下的類庫,啟動類加載器無法被應用程序直接使用;
  • 擴展類加載器(Extension ClassLoader):該加載器器是用JAVA編寫,且它的父類加載器是 Bootstrap,是由 sun.misc.Launcher$ExtClassLoader實現的,主要加載 JAVA_HOME/lib/ext 目錄中的類庫。開發者可以這幾使用擴展類加載器;
  • 系統類加載器(App ClassLoader):也稱為應用程序類加載器,負責加載應用程序 classpath 目錄下的所有 .jar 和 .class 文件。它的父加載器為 Extension ClassLoader。

上述三種類加載器的層次關系如下:

Ps:類加載器的體系并不是“繼承”體系,而是委派體系,大多數類加載器首先會到自己的 parent 中查找類或者資源,如果找不到才會到自己本地查找。類加載器的委托行為動機是為了避免相同的類被加載多次。

五、雙親委派模型

1、雙親委派模型

如果以上三種類加載器不能滿足要求的話,程序員還可以自定義類加載器(繼承 java.lang.ClassLoader 類)

它們的層級關系即 自定義類加載器 -> 應用程序加載器 -> 擴展加載器 -> 啟動類加載器,這種層次關系被稱作為雙親委派模型:如果一個類加載器收到了加載類的請求,它會先把請求委托給上層加載器去完成,上層加載器又會委托上上層加載器,一直到最頂層的類加載器;如果上層加載器無法完成類的加載工作時,當前類加載器才會嘗試自己去加載這個類。

2、雙親委派模式優勢

  • 采用雙親委派模式的是好處是 Java 類隨著它的類加載器一起具備了一種帶有先級的層次關系,通過這種層級關可以避免類的重復加載,當父親已經加載了該類時,就沒有必要子 ClassLoader 再加載一次;
  • 其次是考慮到安全因素,Java 核心 api 中定義類型不會被隨意替換,假設通過網絡傳遞一個名為 java.lang.Integer 的類,通過雙親委托模式傳遞到啟動類加載器,而啟動類加載器在核心 Java API 發現這個名字的類,發現該類已被加載,并不會重新加載網絡傳遞的過來的 java.lang.Integer,而直接返回已加載過的 Integer.class,這樣便可以防止核心 API 庫被隨意篡改;
  • 可能你會想,如果我們在 classpath 路徑下自定義一個名為 java.lang.SingleInterge 類呢?該類并不存在 java.lang 中,經過雙親委托模式,傳遞到啟動類加載器中,由于父類加載器路徑下并沒有該類,所以不會加載,將反向委托給子類加載器加載,最終會通過系統類加載器加載該類。但是這樣做是不允許,因為 java.lang 是核心 API 包,需要訪問權限,強制加載將會報出異常 java.lang.SecurityException: Prohibited package name: java.lang 所以無論如何都無法加載成功的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/535486.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535486.shtml
英文地址,請注明出處:http://en.pswp.cn/news/535486.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

新版谷歌瀏覽器開啟Flash支持

瀏覽器地址欄中輸入chrome://version查看Chrome瀏覽器、Flash插件的版本信息。 Chrome 69.0-70.0版本Chrome 71.0-74.0及以后版本谷歌瀏覽器地址欄中輸入【chrome://flags/#enable-ephemeral-flash-permission】,將【Enable Ephemeral Flash Permissions】從【Defau…

深入理解Java虛擬機:Java垃圾回收機制

本篇內容包括:JAVA 垃圾回收機制概述、有哪些內存需要回收、如何回收(標記-清除、標記-整理(標記-清除-壓縮)、復制(標記-復制-清除)、分代收集等算法) 以及 何時進行垃圾回收等內容&#xff01…

深入理解Java虛擬機:Java垃圾回收器

本篇內容包括:7 種 Jvm 垃圾回收器的介紹、對比 以及 對應的 Jvm 參數設置,這 7 種包括了:Serial、ParNew 以及 Parallel Scavenge 三種新生代回收器 和 :Serial Old、Parallel Old 以及 CMS 三種老年代回收器,此外還有…

oracle跨越千年處理

如果指定的兩位年份0-4950-99 如果當前 的兩位年 份是 0-49返回的日期是當前世紀返回的日期是上個世紀50-99返回的日期是下個世紀返回的日期是當前世紀 current yearSpecified DateRR FormatYY Format199527-OCT-9519951995199527-OCT-171951917200127-OCT-1720012017200127-OC…

網絡協議:什么是網絡分層的七四五

本篇內容包括:網絡分層七層、五層、四層網絡協議概念的介紹,IOS 體系結構的介紹與構成、TCP/IP體系結構的簡介及與IOS體系的關系 以及五層體系結構的介紹。 一、七層、五層、四層網絡協議概念 1、關于網絡協議 網絡協議,即是指計算機網絡中…

查看表空間相關命令

默認表空間數據文件大小根據DATA BLOCKS的大小有關,默認最大為32GB表空間達到32G,只能增加數據文件alter tablespace 表空間名 add datafile 數據文件路徑‘ size 500m autoextend on next 100m maxsize 10000M;未達到32G,修改數據文件的擴展…

網絡協議:一文搞懂Socket套接字

本篇內容包括:Socket 套接字的簡介、Socket 套接字的分類、Java 中的 Socket 即 java.net.ServerSocket、java.net.Socket 的使用,以及Java 使用套接字 Scoket 編程的Demo。 一、Socket 簡介 TCP(傳輸控制協議)是一種面向連接的、…

RESETLOGS

使用resetlogs選項,會把當前的日志序號(log sequence number)重設為1,并拋棄所有日志信息。在以下條件時需要使用resetlogs選項: 在不完全恢復(介質恢復); 使用備份控制文件。 使…

網絡協議:透徹解析HTTP協議

本篇內容包括:HTTP 協議定義及其特點概述、關于 URL 定義及分類概述、Request 請求、Response 響應 以及 瀏覽器訪問一個網站的全過程 等內容… 一、HTTP 協議概述 HTTP(HyperText Transfer Protocol) 即 超文本傳輸協議,它是一種…

oracle參數文件和口令文件

外部 審核 口令:記錄超級用戶的用戶名和口令,做sys用戶的安全審核 oracle9以后全部使用sys登錄,但需要使用as sysdba ,之前版本需要使用internal o7字典打開 只要用戶和密碼存在于口令文件,就可以以sysdba登錄&#…

innobackup備份恢復實操步驟--gtid復制(1)(1)

首先在主庫進行備份: 備份命令: Innobackupex --defaults-file/app/dbcluster/sgrdb/mysql/my19103.cnf --no-timestamp --userdbscale --passwordS6000dbscale --host10.157.43.224 --port19103 /data/backup 如果使用setsid: setsid …

Redis系列:Redis的概述與安裝

Redis(Remote Dictionary Server) 是一個使用 C 語言編寫的,開源的(BSD許可)高性能非關系型(NoSQL)的鍵值對數據庫。 本篇內容包括:Redis 簡介(為什么快?為什么單線程?優…

安裝LibreOffice和字體

#/bin/bash # Check if user is root if [ $(id -u) ! "0" ]; thenecho "Error: You must be root to run this script, please use root"exit 1 fi echo 安裝LibreOffice cd /home/ tar -zxvf LibreOffice_6.3.3_Linux_x86-64_rpm.tar.gz cd /home/LibreO…

xtrabackup備份腳本

#!/bin/sh #備份主機 remote_ip100.0.132.160 Master_ip100.20.132.158 VIP100.20.132.166 #備份用戶 userroot #密碼 password00000 # 返回年月日 backup_datedate %F # 返回時分秒 backup_timedate %H-%M-%S # 返回今天是這周的第幾天 backup_week_daydate %u backup_ok0 #備…

Redis系列:使用Redis實現分布式鎖及相關問題

分布式鎖其實就是,控制分布式系統不同進程共同訪問共享資源的一種鎖的實現。如果不同的系統或同一個系統的不同主機之間共享了某個臨界資源,往往需要互斥來防止彼此干擾,以保證一致性。 本篇內容包括:關于 Redis 與 分布式鎖&…

Redis系列:Redis持久化機制與Redis事務

Redis 是個基于內存的數據庫。那服務一旦宕機,內存中數據必將全部丟失。所以丟失數據的恢復對于 Redis 是十分重要的,我們首先想到是可以從數據庫中恢復,但是在由 Redis 宕機時(說明相關工作正在運行)且數據量很大情況…

Java基礎:Java程序設計環境

按應用范圍,Java 可分為 3 個體系,即 Java SE、Java EE 和 Java ME。Java 語言的開發運行,也離不開 Java 語言的運行環境 JRE。沒有 JRE 的支持,Java 語言便無法運行。當然,如果還想編譯 Java 程序,搞搞小開…

負載均衡策略

輪循均衡(Round Robin):每一次來自網絡的請求輪流分配給內部中的服務器,從1至N然后重新開始。此種均衡算法適合于服務器組中的所有服務器都有相同的軟硬件配置并且平均服務請求相對均衡的情況。 我們的業務web服務器都是同樣配置…

Java基礎:Java數據類型

Java 是一種強類型語言,這就意味著必須為每一個變量聲明一種類型。在 Java 中基本數據類型共有 8 種,包括 4 種整型、2 種浮點型、1 種用于表現 Unicode 編碼的字符單元的字符類型 char 和一種用于表示真值的 boolean 類型 ~ 本篇主要記錄內容包括&#…