[轉載] JVM(一):JVM體系結構詳解

參考鏈接: JVM如何工作–JVM體系結構

JVM簡介? ? ? ? JVM是Java程序得以運行的平臺,也是Java程序可以跨平臺的底層支撐,從整體上來看,JVM的主要功能可以分為加載和執行兩大塊。其中類加載器負責.class文件的尋址與加載,執行引擎負責字節碼指令執行及內存的管理等等。下面是JVM一個經典的體系結構圖?

類加載系統:關于類加載體系的詳細說明在另一博客https://blog.csdn.net/w1673492580/article/details/81838835?

運行時數據區宏觀角度:? ? ? ? ?從宏觀角度來看,JVM運行時數據區的各部分劃分很明顯,方法區用于存儲類數據,堆用于存儲Java程序在運行過程中創建的所有對象,棧和PC寄存器屬于線程獨有,棧代表線程執行過程中所有方法調用信息(比如比如入參、局部變量、中間結果,返回信息等等),PC寄存器即計數器,代表指令在主存中的地址,每執行一條指令后PC+1,即指向下一條指令。本地方法棧即通過Java調用本地方法時的相關信息,但與調用Java方法不一樣,調用Java方法時JVM會當前Java棧中壓入一個新的棧楨,而調用本地方法則不會修改Java棧,從這個角度看,本地方法棧可以理解成JVM運行時數據區的一個擴展。?

微觀角度:堆:Java程序在運行過程中(加載也是運行的一部分)創建的所有對象都位于堆內存中,且JVM中堆內存在設計上是多線程共享的,所以堆中數據的訪問也必須進行安全控制;? ? ? ? 由于運行期間很可能會創建大量的對象,而且大部分對象都是小而短的(占用空間小及生命周期短),所以堆內存的管理也尤其重要,但JVM中并沒有釋放對象的指令,這表示開發中不能通過代碼去管理對象的釋放,所以JVM內置了垃圾回收器來管理,堆也是垃圾回收主要集中的地方(對于棧由于棧楨的大小可以在編譯期就根據類結構數據確定,所以這部分的回收具有一定的確定性)。? ? ? ?在Java代碼中,通過obj.getClass()獲取對象所屬的類,也可以通過new? ClassName()創建一個對象。這是因為在JVM中對象數據包含了一個指向方法區中對應類型信息的指針,可以通過該指針獲取對應類信息。反過來JVM也可以根據方法區中類信息創建該類對象,甚至知道該類對象應該占用多少空間(但實際分配大小依賴于JVM實現)。同樣通過class.getClassLoader()可以獲取當前類加載器也是同樣的原理。? ? ? ? 還有個比較有意思的就是對象鎖synchronized(obj),Java中每個對象都可以作為鎖,同樣也是因為對象本身包含了一個指向鎖數據的指針,但由于絕大部分對象的鎖都用不到,所以大部分JVM的實現,都只在第一個線程嘗試獲取對象鎖時,才給該對象分配對應的鎖數據。? ? ? ?關于堆空間本身的設計依賴具體的實現,下面是兩種完全不同的可能設計,第一種把堆內存劃分為句柄池和對象池兩部分,對對象的引用指向句柄池,句柄池中每個元素又由兩部分組成,一個指向方法區中的存放類數據的地址,一個指向對象池中的對象。這樣的優勢體現在,當垃圾回收器 回收內存并重新劃分導致對象內存地址發生變化時,不需要更新所有引用的指向,而只需要更新句柄池中指向對象的指針,缺點就是中間需要額外經過一次查找。?

第二種設計引用直接指向堆中的對象,這樣的優缺點和第一種設計剛好相反,不需要額外的查找,但對象地址發生變化時,需要更新所有引用。?

方法區:方法區在設計上也是所有線程共享,主要存儲類相關信息(如字段/方法信息、常量池信息、對當前ClassLoader和Class的引用等等),在JVM加載某個類時,會抽取出對應.class文件中類相關的信息并以某種結構(依賴于JVM實現)存到方法區中,當程序運行時,JVM則會到方法區中去查找使用對應類信息(比如創建對象)。? ? ? ? 值得注意的一點是由于所有線程共享方法區中的數據,所以方法區中數據的訪問必須被設計成線程安全的,比如說多個線程并發加載同一類等等。另外方法區雖然也被稱為“永久代”,但實際上其中的數據也是可以被垃圾回收器回收的,回收內容主要包括常量池中無用的常量、無用的類(具體判斷依據請參考垃圾回收篇)。? ? ? ? ?雖然類信息具體的存儲結構依賴于具體JVM實現,但為了提高方法的檢索效率,部分JVM實現會為每個非抽象類生成一個方法表(方法表雖然加快了檢索速度,但本身也會占用一定的內存空間,算是以空間換時間),方法表是一種數組結構,每個元素代表一個方法實例(從Java角度來說,每個元素就相當于一個Method對象)。這種情況下,對象不再直接指向方法區中的存放類信息的地址,而是指向方法表,通過方法表來間接關聯對象與類型信息,從JVM的角度來看其基本指向如下圖?

Java棧與PC寄存器:JVM中每個線程都有自己的PC寄存器和Java棧,PC寄存器即計數器,表示指令在主存中的地址,每執行一條指令后PC+1,即指向下一條指令。Java棧代表線程在執行過程中的所有方法調用信息,JVM對棧只有壓入棧楨和彈出棧楨兩個操作,“棧”由"棧楨“組成,線程每調用一次方法JVM即會為它產生并壓入一個“棧楨”,方法執行完畢即會彈出對應的棧楨,棧楨本質上就是一個內存片,用來存儲方法局部變量和計算的中間結果,其中用于存儲中間結果的部分又稱為“操作數棧”,所以操作的數據即可能是“操作數棧”中的數據,也可能是“棧楨”中的數據。 值得注意的是局部變量和操作數棧的大小在編譯時計算出來,并放置到class文件中,然后JVM就可以知道方法棧楨的大小,當調用一個方法時jvm將壓入一個適當大小的棧楨至棧中,但棧在jvm中是有深度限制的,當線程調用的棧深度超出該限制時將拋出StockOverflowErro異常,如果jvm在擴展棧時無法獲取更多內存則會拋出OutofMemoryErro。下面關于Java棧的圖文描述及驗證代碼? ?

public static void main(String[] args) throws InterruptedException {

//? ? ? ? ?testStackOverflowError();

? ? ? ? testOutOfMemoryError();

? ? }

? ??

? ? public static void testStackOverflowError(){

? ? ? ? testStackOverflowError();

? ? }

? ??

? ? public static void testOutOfMemoryError(){

? ? ? ? byte[] bytes = new byte[2000000000];

? ? }?

本地方法棧:? ? ? ? 本地方法棧即代表了線程在執行過程中調用本地方法的一系列信息,與Java棧不同的地方在于,本地方法并不受JVM的限制,對本地方法的調用不會導致JVM往Java棧中壓入棧楨。關于本地方法與Java方法的調用可以簡單的假設一下,假設某個線程在執行Java方法過程中調用了本地方法C1,且本地方法C1最終又調用了某Java方法,則在這個過程中JVM會先由Java棧進入本地方法棧最終又回到Java棧中,下圖簡單的描述了這種情況?

執行引擎:? ? ? ? 執行引擎負責字節碼指令的執行,方法的字節碼流由一系列有序指令組成,指令又由一個單字節的操作碼 + 0個或多個操作數組成。操作碼表示需要執行的操作,操作數表示操作的數據,一般來源于當前棧楨中的局部變量或當前Java棧楨中操作數棧的頂部,至于操作數的個數,由操作碼決定(操作碼本身就決定了它是否需要操作數,以及操作數的形式等等)。? ? ? ? 不同的JVM中執行引擎也可能不同,最簡單同時效率也最低的執行引擎是一次性解釋字節碼,它在每次運行方法時都把字節碼翻譯成本地代碼再執行; 其次是即時編譯(JITC),它在第一次執行方法時,會把對應的字節碼翻譯成本地機器代碼并緩存,后續調用就可以重用緩存的本地機器代碼;另外一種是自適應優化器(特殊的即時編譯器), JVM一開始也會解釋字節碼,但它會監視程序的活動,并記錄活動過程中使用最頻繁的代碼,然后把這些代碼編譯成本地代碼,而其它代碼則繼續采用解釋的方式。下面是javap -c com.alibaba.fastjson.JSONObject.class反匯編后的部分信息?

?public static java.lang.String valueToString(java.lang.Object) throws org.zend.sdklib.internal.utils.json.JSONException;

? ?Code:

? ? ? 0: aload_0

? ? ? 1: ifnull? ? ? ? 12

? ? ? 4: aload_0

? ? ? 5: aconst_null

? ? ? 6: invokevirtual #304? ? ? ? ? ? ? ? // Method java/lang/Object.equals:(Ljava/lang/Object;)Z

? ? ? 9: ifeq? ? ? ? ? 16

? ? ?12: ldc_w? ? ? ? ?#261? ? ? ? ? ? ? ? // String null

? ? ?15: areturn

? ? ?16: aload_0

? ? ?17: instanceof? ? #635? ? ? ? ? ? ? ? // class org/zend/sdklib/internal/utils/json/JSONString

? ? ?20: ifeq? ? ? ? ? 83

? ? ?23: aload_0

? ? ?24: checkcast? ? ?#635? ? ? ? ? ? ? ? // class org/zend/sdklib/internal/utils/json/JSONString

? ? ?27: invokeinterface #637,? 1? ? ? ? ? // InterfaceMethod org/zend/sdklib/internal/utils/json/JSONString.toJSONString:()Ljava/lang/String;

? ? ?32: astore_1

? ? ?33: goto? ? ? ? ? 46

? ? ?36: astore_2

? ? ?37: new? ? ? ? ? ?#52? ? ? ? ? ? ? ? ?// class org/zend/sdklib/internal/utils/json/JSONException

? ? ?40: dup

? ? ?41: aload_2

? ? ?42: invokespecial #640? ? ? ? ? ? ? ? // Method org/zend/sdklib/internal/utils/json/JSONException."<init>":(Ljava/lang/Throwable;)V

? ? ?45: athrow

? ? ?46: aload_1

? ? ?47: instanceof? ? #92? ? ? ? ? ? ? ? ?// class java/lang/String

? ? ?50: ifeq? ? ? ? ? 58

? ? ?53: aload_1

? ? ?54: checkcast? ? ?#92? ? ? ? ? ? ? ? ?// class java/lang/String

? ? ?57: areturn

? ? ?58: new? ? ? ? ? ?#52? ? ? ? ? ? ? ? ?// class org/zend/sdklib/internal/utils/json/JSONException

? ? ?61: dup?

aload_0表示將第一個局部變量壓入到當前操作數棧中,aload指令后跟著的操作數必須是對象引用,這里第一個局部變量也是引用,即參數Object。 ifnull 12表示彈出棧頂對象(即剛壓入的參數obj),判斷是否為null, 為null則跳轉到偏移量為12的分支處,關于指令相關的更多信息這里就不說了

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

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

相關文章

數據庫連接池的設計思路及java實現

2019獨角獸企業重金招聘Python工程師標準>>> connectionPool.DBConnectionManager [java] view plain copy package connectionPool; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; i…

[轉載] java虛擬機 jvm 出入java棧 棧空間內存分配

參考鏈接&#xff1a; Java虛擬機(JVM)堆棧區域 java棧空間是一塊線程私有的內存空間&#xff0c;java堆和程序數據密切相關&#xff0c;那么java棧就是和線程執行密切相關。線程最基本的執行行為就是函數的調用。每次函數調用其實是通過java棧傳遞數據的。 數據結構中的棧的…

SVN命令行更新代碼

命令列表 svn help查看幫助信息 Available subcommands: add auth blame (praise, annotate, ann) cat changeli…

[轉載] Java中Runtime的使用

參考鏈接&#xff1a; Java中的JVM的關閉掛鉤 1 JDK中Runtime的定義 http://blog.csdn.net/lysnow_oss/archive/2007/05/12/1606349.aspx <轉載> 那就首先說點Runtime類吧&#xff0c;他是一個與JVM運行時環境有關的類&#xff0c;這個類是Singleton的。我…

窄帶物聯網(NB-IoT)初步了解

哪有什么天生如此&#xff0c;只是我們天天堅持。既然總有人要贏的話&#xff0c;為什么不能是我呢&#xff1f;[TOC] 什么是NB-Iot? 基于蜂窩的窄帶物聯網&#xff08;Narrow Band Internet of Things, NB-IoT&#xff09;成為萬物互聯網絡的一個重要分支。NB-IoT構建于蜂窩網…

ai人工智能_人工智能能力問答中的人工智能不確定性

ai人工智能1) Which of the following is true with respect to uncertainty in AI systems? Uncertainty arises when we are not 100 percent confident in our decisionsWhenever uncertainty arises, there is needs to be an estimation taken for getting to any conclu…

[轉載] 弄懂JDK、JRE和JVM到底是什么

參考鏈接&#xff1a; JDK JRE和JVM之間的區別 首先是JDK JDK(Java Development Kit) 是 Java 語言的軟件開發工具包(SDK)。 在JDK的安裝目錄下有一個jre目錄&#xff0c;里面有兩個文件夾bin和lib&#xff0c;在這里可以認為bin里的就是jvm&#xff0c;lib中則是jvm工作所需要…

mcq 隊列_人工智能搜索問題能力問題解答(MCQ)

mcq 隊列1) The main Aim of the AI system is to provide a solution for real-life problems by acting and thinking humanly. Whenever an agent is confronted by a problem, what is the first step that it follows towards searching a solution to the problem? Sear…

JavaOne大事紀:IBM談OpenJ9和Open Liberty

JavaOne大會以IBM陳述其最近對開源社區的貢獻作為開場&#xff1a;OpenJ9、Open Liberty和MicroProfile。IBM杰出工程師John Duimovich做了“IBM和Java&#xff1a;助力下一代創新”的開場演講。\\讀者可以回看演講視頻。\\Duimovich說IBM之所以致力于推動Java生態系統的創新&a…

[轉載] JVM中對象的回收過程

參考鏈接&#xff1a; JVM是否創建Main類(具有main()的類)的對象 當我們的程序開啟運行之后就&#xff0c;就會在我們的java堆中不斷的產生新的對象&#xff0c;而這是需要占用我們的存儲空間的&#xff0c;因為創建一個新的對象需要分配對應的內存空間&#xff0c;顯然我的內…

c語言格式對齊填充_C ++中類的大小 課堂上的填充和對齊| 派生類的大小

c語言格式對齊填充Prerequisite: 先決條件&#xff1a; sizeof() operator in C/C C / C 中的sizeof()運算符 Size of struct in C C中的struct大小 We know that a struct size is not only the summation of all the data members, rather its the minimum sum guaranteed. …

ELK系列~對fluentd參數的理解

這段時候一直在研究ELK框架&#xff0c;主要集成在對fluentd和nxlog的研究上&#xff0c;國內文章不多&#xff0c;主要看了一下官方的API&#xff0c;配合自己的理解&#xff0c;總結了一下&#xff0c;希望可以幫到剛入行的朋友們&#xff01; Fluentd&#xff08;日志收集與…

[轉載] Java中的50個關鍵字

參考鏈接&#xff1a; Java平臺如何獨立 Java中的50個關鍵字 關鍵字也稱為保留字&#xff0c;是指java語言中規定了特定含義的標示符。對于保留字&#xff0c;用戶只能按照系統規定的方式使用&#xff0c;不能自行定義。Java中有50個常用關鍵字&#xff1a; 與數據類型相關…

MySQL 直接存儲圖片并在 html 頁面中展示,點擊下載

數據庫實體類&#xff1a; package com.easy.kotlin.picturecrawler.entityimport java.util.* import javax.persistence.*Entity Table(indexes arrayOf(Index(name "idx_url", unique true, columnList "url"),Index(name "idx_category"…

css 文本背景色透明_如何使用CSS將文本或圖像的背景設置為透明?

css 文本背景色透明Introduction: 介紹&#xff1a; In web development, there are numerous ways by which we can style our websites or web pages. You can make use of lots of properties for creating attractive and responsive websites. 在Web開發中&#xff0c;我…

[轉載] 1.1Java使用JDBC原生方式連接MySql數據庫

參考鏈接&#xff1a; Java數據庫連接JDBC驅動程序 前言&#xff1a;今天有朋友問我原生的java連接數據庫&#xff0c;因為框架的使用&#xff0c;如果基礎不牢固的人&#xff0c;是很容易遺忘原生的連接方式。今天正好趁此做一下回顧&#xff1a; 這里只考慮原生方式&#x…

maven安裝及集成myeclipse

第一步&#xff1a;下載和安裝 1、官網下載Maven&#xff1a;http://maven.apache.org/download.cgi 2、解壓到一個文件夾2、設置環境變量&#xff1a;如&#xff1a;M2_HOME&#xff1a;D:\JAVA\apache-maven-3.0.5在path中添加;%M2_HOME%\bin;第二步&#xff1a;和MyEclipse集…

[轉載] Java泛型詳解:<T>和Class<T>的使用。泛型類,泛型方法的詳細使用實例

參考鏈接&#xff1a; Java中的main()函數是強制性的嗎 一、引入 1、泛型是什么 首先告訴大家ArrayList就是泛型。那ArrayList能完成哪些想不到的功能呢&#xff1f;先看看下面這段代碼&#xff1a; [java] view plain copy ArrayList<String> strList new ArrayL…

數字和數字根的總和_使用8086微處理器查找8位數字的數字總和

數字和數字根的總和Problem statement: 問題陳述&#xff1a; Write an assembly language program in 8086 microprocessor to find sum of digit of an 8 bits number using 8 bits operation. 在8086微處理器中編寫匯編語言程序&#xff0c;以使用8位運算找到8位數字的位數…

[轉載] Java筆試題集錦

參考鏈接&#xff1a; 關于Java中文件名和類名的誤解 Java筆試題集錦 1.MVC的各個部分都有那些技術來實現?如何實現? 答&#xff1a;MVC是Model&#xff0d;View&#xff0d;Controller的簡寫。"Model" 代表的是應用的業務邏輯&#xff08;通過JavaBean&#xff…