echart實例數據 本地加載_JVM 類加載概述

來源:SegmentFault 思否社區

作者:又壞又迷人


JVM簡介

JVM是Java Virtual Machine(Java虛擬機)的縮寫,JVM是一種用于計算設備的規范,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。Java虛擬機包括一套字節碼指令集、一組寄存器、一個棧、一個垃圾回收堆和一個存儲方法域。JVM屏蔽了與具體操作系統平臺相關的信息,使Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。JVM在執行字節碼時,實際上最終還是把字節碼解釋成具體平臺上的機器指令執行。

Java語言的一個非常重要的特點就是與平臺的無關性。而使用Java虛擬機是實現這一特點的關鍵。一般的高級語言如果要在不同的平臺上運行,至少需要編譯成不同的目標代碼。而引入Java語言虛擬機后,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。這就是Java的能夠“一次編譯,到處運行”的原因。


內存結構概述

0faf1046d533fbc926e2849547e7c402.png

448f134c7dad2df4547b75dd1178cd69.png

類加載子系統(Class Loader)

類加載器分為:自定義類加載器 < 系統類加載器 < 擴展類加載器 < 引導類加載器

類加載過程分為:加載、鏈接、驗證、初始化。

程序計數器(Program Counter Register)

是一塊較小的內存空間,可以看作是當前線程所執行字節碼的行號指示器,指向下一個將要執行的指令代碼,由執行引擎來讀取下一條指令。

虛擬機棧 (Stack Area)

棧是線程私有,棧幀是棧的元素。每個方法在執行時都會創建一個棧幀。棧幀中存儲了局部變量表、操作數棧、動態連接和方法出口等信息。每個方法從調用到運行結束的過程,就對應著一個棧幀在棧中壓棧到出棧的過程。

本地方法棧 (Native Method Area)

JVM 中的棧包括 Java 虛擬機棧和本地方法棧,兩者的區別就是,Java 虛擬機棧為 JVM 執行 Java 方法服務,本地方法棧則為 JVM 使用到的 Native 方法服務。

堆 (Heap Area)

堆是Java虛擬機所管理的內存中最大的一塊存儲區域。堆內存被所有線程共享。主要存放使用new關鍵字創建的對象。所有對象實例以及數組都要在堆上分配。垃圾收集器就是根據GC算法,收集堆上對象所占用的內存空間。

Java堆分為年輕代(Young Generation)和老年代(Old Generation);年輕代又分為伊甸園(Eden)和幸存區(Survivor區);幸存區又分為From Survivor空間和 To Survivor空間。

方法區(Method Area)

方法區同 Java 堆一樣是被所有線程共享的區間,用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼。更具體的說,靜態變量+常量+類信息(版本、方法、字段等)+運行時常量池存在方法區中。常量池是方法區的一部分。

JDK 8 使用元空間 MetaSpace 代替方法區,元空間并不在JVM中,而是在本地內存中

類加載過程概述

類加載器子系統負責從文件系統或者網絡中在家Class文件,class文件在文件開頭又特定的文件標識。

ClassLoader只負責class文件的加載,至于它是否可以運行,則由ExecutionEngine決定。

加載類的信息存放于一塊被稱為方法區的內存空間。除了類的信息外,方法區中還會存放運行時常量池信息,可能還包括字符串字面量和數字常量(這部分常量信息是Class文件中常量池部分的內存映射)


類加載器ClassLoader角色

4a24fb4ae354239163bf445a2db3348a.png

  1. class文件存在本地硬盤上,在執行時加載到JVM中,根據這個文件可以實例化出n個一模一樣的實例。
  2. class文件加載到JVM中,被稱為DNA元數據模板,放在方法區中。
  3. 在.class文件 -> JVM -> 最終成為元數據模板的過程中,ClassLoader就扮演一個快遞員的角色。


類加載過程概述

7f24e4245c24fabd81fcd3b16879cdac.png

8e872d3afa98e83c0a8ccb0293490687.png

7c0bff82937f54724bb06ec14c043148.png

類的加載過程大致分為三個階段:加載,鏈接,初始化。


類的加載過程一:加載(Loading)

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

類的加載過程二:鏈接(Linking)

驗證(Verify)

  1. 目的在于確保Class文件的字節流中包含信息符合當前虛擬機要求,保證被加載類的正確性,不會危害到虛擬機的安全。

準備(Prepare)

準備階段是進行內存分配。為類變量也就是類中由static修飾的變量分配內存,并且設置初始值,這里要注意,初始值是默認初始值0、null、0.0、false等,而不是代碼中設置的具體值,代碼中設置的值是在初始化階段完成的。另外這里也不包含用final修飾的靜態變量,因為final在編譯的時候就會分配了。這里不會為實例變量分配初始化,類變量會分配在方法區中,而實例對象會隨著對象一起分配到Java堆中。

public class HelloApp {    private static int a = 1; // 準備階段為0,而不是1    public static void main(String[] args) {        System.out.println(a);    }}

解析(Resolve)

解析主要是解析字段、接口、方法。主要是將常量池中的符號引用替換為直接引用的過程。直接引用就是直接指向目標的指針、相對偏移量等。


類的加載過程三:初始化(initialization)

  1. 初始化階段就是執行類構造器方法()的過程
  2. 此方法不需要定義,是javac編譯期自動收集類中所有類變量的賦值動作和靜態代碼塊中的語句合并而來
  3. 構造器方法中指令按語句在源文件中出現的順序執行。
  4. ()不同于類的構造器(構造器是虛擬機視角下的())
  5. 若該類具有父類,JVM會保證子類的()執行前,父類的()已經執行完畢
  6. 虛擬機必須保證一個類的()方法在多線程下被同步加鎖

需要注意,如果沒有定義靜態變量或靜態代碼塊的話則沒有()

案例如下:

public class HelloApp {    static {        code = 20;    }    private static int code = 10;    //第一步:在準備階段初始化了code默認值為0。    //第二步:根據類執行順序先執行靜態代碼塊,賦值為20.    //第三步:最后賦值為10,輸出結果為10.    public static void main(String[] args) {        System.out.println(code); // 10    }}

通過字節碼文件可以很清楚的看到結果:

 0 bipush 20 2 putstatic #3  5 bipush 10 7 putstatic #3 10 return

先被賦值為20,然后改為10。


類加載器概述

JVM支持兩種類型的類加載器,分別為引導類加載器(Bootstrap ClassLoader)?和?自定義類加載器(User-Defined ClassLoader)

從概念上講,自定義類加載器一般指的是程序中由開發人員自定義的一類類加載器,但是Java虛擬機是將所有派生于抽象類ClassLoader的類加載器都劃分為自定義類加載器

無論怎么劃分,在程序中最常見的類加載器始終只有三個:

系統類加載器(System Class Loader) < 擴展類加載器(Extension Class Loader) < 引導類加載器(Bootstrap Class Loader)

它們之間的關系不是繼承關系,而是level關系。

0f96c9481bef98dd4d429001004cb0e3.png

系統類加載器和擴展類加載器間接或直接繼承ClassLoader。劃線分為兩大類。

6490053fabff532a478d5e95ae81b33c.png

public class HelloApp {    public static void main(String[] args) {        //獲取系統類加載器        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();        System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2        //獲取其上層:擴展類加載器        ClassLoader extClassLoader = systemClassLoader.getParent();        System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@60e53b93        //獲取其上層:獲取不到引導類加載器        ClassLoader bootStrapLoader = extClassLoader.getParent();        System.out.println(bootStrapLoader);//null        //我們自己定義的類是由什么類加載器加載的:使用系統類加載器        ClassLoader classLoader = HelloApp.class.getClassLoader();        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2        //看看String是由什么類加載器加載的:使用引導類加載器        ClassLoader classLoaderString = String.class.getClassLoader();        System.out.println(classLoaderString);//null    }}

引導類加載器(Bootstrap ClassLoader)

  1. 這個類加載使用c/c++語言實現,嵌套在JVM內部。
  2. 他用來加載Java的核心庫,(JAVA_HOME/jre/lib/rt.jar、resources.jar、或sun.boot.class.path路徑下的內容),用于提供JVM自身需要的類。
  3. 并不繼承自java.lang.ClassLoader ,沒有父加載器。
  4. 加載擴展類和應用程序類加載器,并指定為他們的父類加載器。
  5. 出于安全考慮,Bootstrap啟動類加載器只加載包名為java、javax、sun等開頭的類。

擴展類加載器(Extension ClassLoader)

  1. Java語言編寫,由sun.misc.Launcher$ExtClassLoader實現。
  2. 派生于ClassLoader類。
  3. 上一層類加載器為啟動類加載器。
  4. 從java.ext.dirs系統屬性所指定的目標中加載類庫,或從JDK的安裝目錄jre/lib/ext子目錄(擴展目錄)下加載類庫。如果用戶創建的Jar放在此目錄下,也會自動由擴展類加載器加載。

系統類加載器(System ClassLoader)

  1. Java語言編寫,由sun.misc.Launcher$AppClassLoader實現。
  2. 派生于ClassLoader類。
  3. 上一層類加載器為擴展類加載器。
  4. 它負責加載環境變量classpath或系統屬性 java.class.path指定下的類庫。
  5. 該類加載是程序中默認的類加載器,一般來說,Java應用的類都有由它來完成加載。
  6. 通過ClassLoader.getSystemClassLoader()方法可以獲取該類加載器。

為什么需要用戶自定義類加載器?

  • 隔離加載類
  • 修改類加載的方式
  • 擴展加載源
  • 防止源碼泄露

用戶自定義類加載器實現步驟

  1. 通過集成抽象類java.lang.ClassLoader類的方式,實現自己的類加載器。
  2. 在JDK1.2之前,在自定義類加載器時,總會去繼承ClassLoader類并重寫loadClass()方法,從而實現自定義的類加載器,但是在JDK1.2之后不再建議用戶去覆蓋loadClass()方法,而是建議把自定義類加載邏輯寫在findClass()方法中。
  3. 在編寫自定義類加載器時,如果沒有太過于復雜的需求,可以直接繼承URLClassLoader類,這樣就可以避免自己編寫findClass()方法其獲取字節碼流的方式,使得自定義加載器編寫更為簡潔。

關于ClassLoader

ClassLoader是一個抽象類,系統類加載器和擴展類加載器間接或直接繼承ClassLoader。

常用方法如下:

0e850d9703a7e32f39d3ca2686c1b1c1.png


雙親委派機制

Java虛擬機對class文件采用的是按需加載的方式,也就是說需要使用該類的時候才會將它的class文件加載到內存生成class對象。

當某個類加載器需要加載某個.class文件時,它首先把這個任務委托給他的上級類加載器,遞歸這個操作,如果上級的類加載器沒有加載,自己才會去加載這個類。

工作原理

9e1acbd1e803e86793af583fcc7b64f9.png

  1. 如果一個類加載器收到了類加載請求,他并不會自己先去加載,而是把這個請求向上委托給上一級類加載器去執行。
  2. 如果上一級類加載器還存在上一級,則進一步向上委托,依次遞歸,請求最終會達到引導類加載器。
  3. 如果引導類加載器可以完成類加載任務,就成功返回。如果無法完成類加載任務,會依次往下再去執行加載任務。這就是雙親委派機制。

比如我們現在在自己項目中創建一個包名java.lang下創建一個String類。

package java.lang;public class String {    static {        System.out.println("我是自己創建的String");    }}
public class HelloApp {    public static void main(String[] args) {        String s = new String();    }}

執行之后并不會輸出我們的語句,因為我們的String類加載器一開始由系統類加載器一級一級往上委托,最終交給引導類加載器,引導類加載器一看是java.lang包下的,ok,我來執行,最終執行的并不是我們自己創建String類,保證了核心api無法被纂改,避免類的重復加載。

package java.lang;public class String {    static {        System.out.println("我是自己創建的String");    }    public static void main(String[] args) {        System.out.println("Hello World !!!");    }}

如果我們想運行如上代碼,我們會得到如下錯誤:

錯誤: 在類 java.lang.String 中找不到 main 方法, 請將 main 方法定義為:   public static void main(String[] args)否則 JavaFX 應用程序類必須擴展javafx.application.Application

因為我們知道在核心api String類中是沒有main方法的,所以我們可以確定加載的并不是我們自己創建的String類。

在JVM中表示兩個Class對象是否為同一個類存在的必要條件:

  • 類的完整類名必須一致,包括包名。
  • 加載這個類的ClassLoader也必須相同。

順便說一句,我們包名如果為java.lang則會報錯。


-?END -

6b6abee9d2df0946218b76b1d97c5622.png

3e169ea37041bd9ca252a627e29a4eb2.gif

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

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

相關文章

JPA / Hibernate:基于版本的樂觀并發控制

本文是Hibernate和JPA中基于版本的樂觀并發控制的簡介。 這個概念已經很老了&#xff0c;上面已經寫了很多東西&#xff0c;但是無論如何我都看到了它被重新發明&#xff0c;誤解和濫用。 我在編寫它只是為了傳播知識&#xff0c;并希望引起人們對并發控制和鎖定的興趣。 用例…

高可用集群搭建

高可用集群搭建  創建hadoop賬戶 創建hadoop賬戶&#xff08;#注意&#xff0c;接下來的操作均在hadoop賬戶下運行&#xff09; # useradd hadoop # passwd hadoopsu - hadoopmkdir soft disk1 disk2mkdir -p disk{1,2}/dfs/{dn,nn}mkdir -p disk{1,2}/nodemgr/local 將本地目…

scrt如何切換成英文版_英文版SecureCRT顯示亂碼解決

英文版SecureCRT顯示亂碼解決系統環境&#xff1a;CentOS&#xff15;.&#xff16;以前Linux都是默認安裝在英文環境下&#xff0c;用英文版的SecureCRT查看系統內容輸出的也都是英文的&#xff0c;不會出現亂碼問題。今天同事在服務器安裝時默認選擇了簡體中文&#xff0c;這…

java try catch_Java捕獲異常

大家好&#xff0c;歡迎來到樂字節小樂的Java技術分享園地在Java中&#xff0c;凡是可能拋出異常的語句&#xff0c;都可以用try ... catch捕獲。把可能發生異常的語句放在try { ... }中&#xff0c;然后使用catch捕獲對應的Exception及其子類。多catch語句可以使用多個catch語…

haproxy文件操作

import os #導入os模塊def search(): #定義查找函數 with open(haproxy.txt,r) as f: #只讀方式打開文件 value input(請輸入您…

多語言持久性:帶有MongoDB和Derby的EclipseLink

從現在開始&#xff0c;多語種持久性一直是新聞。 從2011年底開始&#xff0c;在著名的Fowler帖子的推動下&#xff0c;我看到了更多更好的主意。 最新的一個是公司內部的學生項目&#xff0c;我們在其中使用Scala作為后端數據&#xff0c;將數據持久存儲到MongoDB&#xff0c;…

web前端開發最佳實踐--(筆記之JavaScript最佳實踐)

如何避免全局變量污染&#xff1f; 避免定義全局變量或全局函數用一個變量進行封裝&#xff0c;并返回外部需要訪問的接口如何寫出高維護的js代碼 配置數據和代碼邏輯分離 如&#xff1a; 改成&#xff1a; ---用js模板mustachehandlebarsjsMVC的數據模式 model&#xff1a;數據…

yum mysql5.7位置_CentOS yum 安裝 Mysql5.7

1 Steps for a Fresh Installation of MySQL# wget https://dev.mysql.com/get/mysql57-community-release-el6-9.noarch.rpm# yum localinstall mysql57-community-release-el6-9.noarch.rpm以上步驟其實是把 MySQL Yum repository 添加到了系統的 repository list 里去了。ll…

HTML/CSS基礎知識(四)

WEB標準和W3C的理解與認識 Web標準是一系列標準的集合。 網頁主要由三部分組成&#xff1a;結構&#xff08;Structure&#xff09;、表現&#xff08;Presentation&#xff09;和行為&#xff08;Behavior&#xff09;。 對應的標準也分三方面&#xff1a;結構化標準語言主要包…

python做一個系統代碼_python初學者,用python3實現基本的學生管理系統代碼實例...

這篇文章分享了管理系統&#xff0c;python學生管理系統的使用&#xff0c;這篇文章非常詳細地介紹了通過示例代碼實現的學生管理系統&#xff0c;該系統對每個人的研究或工作都有一定的參考學習價值。 這個是用python實現的基本的增刪改查的學生管理系統吧&#xff0c;其中主要…

Python入門筆記

Python變量和數據類型 數據類型 print語句 注釋 Python的注釋以 # 開頭&#xff0c;后面的文字直到行尾都算注釋 # 這一行全部都是注釋... print hello # 這也是注釋 什么是變量 定義字符串 字符串可以用或者""括起來表示。 如果字符串本身包含怎么辦&#xff1f;比如…

1058. 選擇題(20)

原題: https://www.patest.cn/contests/pat-b-practise/1058 思路: 本題主要就是怎么讀取數據的問題, 一定要注意scanf函數匹配到 空格或者回車會結束當前變量的賦值, 并且會丟棄這個空格或回車. 關于如何判斷一項答題是否正確, 可以采用循環一個一個判斷, 也可拼成 字符串用st…

使用Spring和Hibernate進行集成測試有多酷

我有罪&#xff0c;直到現在才寫集成測試&#xff08;至少針對數據庫相關事務&#xff09;。 因此&#xff0c;為了消除內感&#xff0c;我閱讀了如何在周末以最少的努力實現這一目標。 提供了一個小示例&#xff0c;描述了如何使用Spring和Hibernate輕松實現這一目標。 通過集…

假設mysql數據表t1有字段_使用ROMA Connect集成數據

概述ROMA Connect支持接入多種類型的數據源&#xff0c;并通過數據集成任務實現源端到目標端的數據集成轉換。ROMA Connect支持相同結構數據之間進行集成轉換&#xff0c;也支持異構數據之間進行集成轉換。本章節通過完成一個SQL Server到MySQL的數據集成配置樣例&#xff0c;幫…

vue-wechat-title

html中的title安裝&#xff1a;npm install vue-wechat-title --save1.在mian.js中//網頁titleimport VueTitle from vue-wechat-title Vue.use(VueTitle);2. 路由中加下 title { path: /, component: Index, meta: { title: 首頁 } }3. 在app.vue 中修改 router-view &a…

如何保證input的輸入值不會隨著提交 而變空_如何對web界面的應用進行測試?

一、輸入框&#xff1a;1、字符型輸入框&#xff1a;&#xff08;1&#xff09;字符型輸入框&#xff1a;英文全角、英文半角、數字、空或者空格、特殊字符“~&#xff01;#&#xffe5;%……&*&#xff1f;[]{}”特別要注意單引號和&符號。禁止直接輸入特殊字符時&…

CentOS6.x下,tomcat - web項目部署

1. 安裝tomcat tomcat安裝方法&#xff1a;http://www.cnblogs.com/vurtne-lu/p/6478440.html 2. 配置tomcat 修改server.xml文件 <!-- 使用 80 端口 (也可以使用其它端口)--> <Connector port"80" protocol"HTTP/1.1"connectionTimeout"200…

dedecms列表頁面隨機縮略圖調用

如果要利用dedecms制作扁平化主題&#xff0c;大概也能夠遇到相似的問題&#xff0c;那就是dedecms的縮略圖機制&#xff0c;在沒有縮略圖的情況下顯示單一的默認圖片&#xff0c;如果是wordpress可以很方便的定義函數調用隨機的縮略圖&#xff0c;即便是在沒有設置縮略圖并且文…

使用地圖觸發功能處理相干事件

本文介紹如何通過使用映射觸發器來處理一致性事件。 基本上&#xff0c;建議使用Oracle Coherence中的分布式數據管理來研究Oracle Coherence API的基本配置和實現。 映射觸發器是Oracle Coherence提供最高度定制的緩存管理系統的最重要功能之一。 MapTrigger代表一個功能代理…

阿里云服務器mysql莫名丟失_mysql數據庫丟失

mysql數據庫丟失云服務器(Elastic Compute Service&#xff0c;簡稱ECS)是阿里云提供的性能卓越、穩定可靠、彈性擴展的IaaS(Infrastructure as a Service)級別云計算服務。云服務器ECS免去了您采購IT硬件的前期準備&#xff0c;讓您像使用水、電、天然氣等公共資源一樣便捷、高…