Jvm基礎(chǔ)知識(shí)下篇

一、java執(zhí)行引擎工作原理:方法調(diào)用

1.進(jìn)行方法調(diào)用

Java語(yǔ)言的原子指令是字節(jié)碼,java方法是對(duì)字節(jié)碼的封裝。
(1)invokestatic:調(diào)用靜態(tài)方法
(2)invokespecial:調(diào)用實(shí)例構(gòu)造器<init>方法、私有方法和父類方法(super(),super.method())
(3)invokevirtual:調(diào)用非私有實(shí)例方法,虛方法表中存放著各個(gè)方法的實(shí)際入口地址。如果某個(gè)方法在子類中沒(méi)有被重寫,那子類的虛方法表里面的地址入口和父類相同簽名的方法的地址入口是一致的,都指向父類的實(shí)現(xiàn)入口。如果子類中重寫了這個(gè)方法,子類方法表中的地址將會(huì)替換為向子類實(shí)現(xiàn)版本的入口地址
(4)invokeinterface:調(diào)用接口方法,會(huì)在運(yùn)行時(shí)期再確定一個(gè)實(shí)現(xiàn)此接口的對(duì)象

2.函數(shù)指針

指向函數(shù)的指針包含了函數(shù)的地址,可以通過(guò)它來(lái)調(diào)用函數(shù),函數(shù)指針與指針函數(shù)的最大區(qū)別是函數(shù)指針的函數(shù)名是一個(gè)指針

3.執(zhí)行邏輯運(yùn)算

物理機(jī)器在調(diào)用函數(shù)時(shí)的一系列操作(1)參數(shù)入棧,(2)代碼指針(3)調(diào)用函數(shù)的棧基地址入棧(4)為被調(diào)用方分配方法棧空間
有參數(shù)傳遞的調(diào)用機(jī)制
(1)保存調(diào)用者棧基地址,當(dāng)前ip寄存器入棧
(2)調(diào)用函數(shù)時(shí),在x86平臺(tái)上,參數(shù)從右到左依次入棧
(3)一個(gè)方法所分配的棧空間大小,取決于該方法內(nèi)部的局部變量空間、為被調(diào)用者所傳遞的入?yún)⒋笮?br> (4)被調(diào)用者在接收入?yún)r(shí),從8(%ebp)處開(kāi)始,往上獲取每一個(gè)入?yún)?shù),之所以從8開(kāi)始,是因?yàn)檫€有ebp棧基地址寄存器和eip這個(gè)ip寄存器
(5)被調(diào)用者將返回結(jié)果保存在eax寄存器中,調(diào)用者從該寄存器中獲取返回值
指針函數(shù)聲明的是一個(gè)函數(shù),與一般的函數(shù)聲明并無(wú)多大區(qū)別,唯一有區(qū)別的就是指針函數(shù)的返回類型是一個(gè)指針,而一般的函數(shù)聲明所返回的則是普通變量類型
函數(shù)指針聲明的是一個(gè)指針,返回的是一個(gè)函數(shù)的首地址。

二、java數(shù)據(jù)結(jié)構(gòu)

1.java數(shù)據(jù)結(jié)構(gòu)

數(shù)據(jù)結(jié)構(gòu)是計(jì)算機(jī)存儲(chǔ),組織數(shù)據(jù)的方式。數(shù)據(jù)結(jié)構(gòu)是指相互之間存在一種或多種特定關(guān)系的數(shù)據(jù)元素的集合。在jvm加載java類的時(shí)候,就將類的類元信息(其實(shí)就是打包好的數(shù)據(jù)結(jié)構(gòu))保存到內(nèi)存中,這樣在運(yùn)行期直接讀取目標(biāo)內(nèi)存中的數(shù)據(jù)便能獲取到相應(yīng)的信息。

2.大端與小端

java采用的是大端序
(1)小端就是低位字節(jié)排放在內(nèi)存的低地址端,高位字節(jié)排放在內(nèi)存的高地址端
(2)大端就是高位字節(jié)排放在內(nèi)存的低地址端,低位字節(jié)排放在內(nèi)存的高地址端
(3)網(wǎng)絡(luò)字節(jié)序,TCP/IP協(xié)議中使用的字節(jié)序通常稱為網(wǎng)絡(luò)字節(jié)序,TCP/IP各層協(xié)議將字節(jié)序定義為大端

三、java字節(jié)碼實(shí)戰(zhàn)

image.png

四、常量池解析

1.java字節(jié)碼常量池的內(nèi)存分配鏈路

(1)在堆區(qū)分配內(nèi)存空間,通過(guò)object_space()->allocate(word_size)實(shí)現(xiàn)(2)初始化對(duì)象,通過(guò)在collectedHeap.inline.hpp中調(diào)用init_obj()進(jìn)行對(duì)象初始化,所謂對(duì)象初始化,其實(shí)僅僅是清零(3)初始化oop,collectedHeap.inline.hpp中調(diào)用post_allocation_install_obj_kclass()完成oop初始化并賦值。JVM內(nèi)部通過(guò)oop-class來(lái)描述一個(gè)java類。一個(gè)java類的實(shí)例數(shù)據(jù)會(huì)被存放在堆中,而為了支持運(yùn)行期反射、虛函數(shù)分發(fā)等高級(jí)操作,java類實(shí)例指針oop會(huì)保存一個(gè)指針,用于指向java類的類描述對(duì)象,類描述對(duì)象中保存一個(gè)java類中所包含的全部成員變量和全部方法信息。

2.oop-kclass模型

OOP 指的是 Ordinary Object Pointer (普通對(duì)象指針),它用來(lái)表示對(duì)象的實(shí)例信息,看起來(lái)像個(gè)指針實(shí)際上是藏在指針里的對(duì)象。而 Klass 則包含元數(shù)據(jù)和方法信息,用來(lái)描述Java類。Klass是在class文件在加載過(guò)程中創(chuàng)建的,OOP則是在Java程序運(yùn)行過(guò)程中new對(duì)象時(shí)創(chuàng)建的。(1)oop用來(lái)表示對(duì)象的實(shí)例信息,包含instanceOopDesc也叫對(duì)象頭,其中mark word主要存儲(chǔ)對(duì)象運(yùn)行時(shí)記錄信息,如hashcode,GC分代年齡,鎖狀態(tài)標(biāo)志,線程ID,時(shí)間戳等,元數(shù)據(jù)指針,指向方法區(qū)的instanceKlass實(shí)例,還有實(shí)例數(shù)據(jù)。(2)klass 用來(lái)表示對(duì)象元數(shù)據(jù)信息,有兩個(gè)功能:實(shí)現(xiàn)語(yǔ)言層面的java類,實(shí)現(xiàn)java對(duì)象的分發(fā)功能。一般jvm在加載class文件時(shí),會(huì)在方法區(qū)創(chuàng)建instanceKlass,表示其元數(shù)據(jù),包括常量池、字段、方法等。


image.png

五、類變量解析

Jvm解析類變量的邏輯:(1)獲取java類中的變量數(shù)量(2)讀取變量的訪問(wèn)標(biāo)識(shí)(3)讀取變量名稱索引(4)讀取變量類型索引(5)讀取變量屬性(6)判斷變量類型(7)統(tǒng)計(jì)各類型數(shù)量。
java類中在堆內(nèi)存中的內(nèi)存空間,主要由java類非靜態(tài)字段占據(jù)。Hotspot解析java類非靜態(tài)字段和分配堆內(nèi)存空間的主要邏輯為:(1)解析常量池,統(tǒng)計(jì)java類中非靜態(tài)字段的總數(shù)量,按照5大類型(oops/longs/doubles/ints/shorts/chars/bytes)分別統(tǒng)計(jì)(2)計(jì)算java類字段的起始偏移量,起始偏移位置從父類繼承的字段域的末尾開(kāi)始(3)按照分配策略,計(jì)算5大類型中的每一個(gè)類型的起始偏移量。(4)以5大類型的起始量為基準(zhǔn),計(jì)算每一個(gè)大類型下各個(gè)具體字段的偏移量(5)計(jì)算java類在堆內(nèi)存中的內(nèi)存空間。
當(dāng)java程序中使用new關(guān)鍵字創(chuàng)建java類的實(shí)例對(duì)象時(shí),HotSpot便會(huì)從instanceKclass中讀取java類所需要的堆內(nèi)存大小并分配對(duì)應(yīng)的內(nèi)存空間。

六、java棧幀

jvm為每個(gè)新創(chuàng)建的線程都分配一個(gè)堆棧。堆棧以幀為單位保存線程的狀態(tài)。jvm對(duì)堆棧只進(jìn)行兩種操作:以幀為單位的壓棧和出棧操作。每一個(gè)棧幀都包括了局部變量表,操作數(shù)棧,動(dòng)態(tài)連接,方法返回地址和一些額外的附加信息。

1.局部變量表創(chuàng)建的機(jī)制

局部變量表是一組變量值存儲(chǔ)空間,用于存放方法參數(shù)和方法內(nèi)部定義的局部變量。在Java程序編譯為Class文件時(shí),就在方法表的Code屬性的max_locals數(shù)據(jù)項(xiàng)中確定了該方法需要分配的最大局部變量表的容量。在方法執(zhí)行時(shí),虛擬機(jī)是使用局部變量表完成參數(shù)變量列表的傳遞過(guò)程,如果是實(shí)例方法,那么局部變量表中的0位索引的Slot默認(rèn)是用于傳遞方法所屬對(duì)象實(shí) 例的引用,在方法中可以通過(guò)關(guān)鍵字“this”來(lái)訪問(wèn)這個(gè)隱含的參數(shù)。

2.jvm棧幀的創(chuàng)建過(guò)程

由于java方法的入?yún)⒑蚸ava方法內(nèi)部的局部變量共同組成了局部變量表,局部變量表作為一個(gè)整體,自然不能被分隔,不能在中間插入一個(gè)return address,因此在對(duì)局部變量進(jìn)行壓棧時(shí),必然要先把return address拿掉,待局部變量全部壓棧完成之后,再將return address恢復(fù)到棧頂(1)恢復(fù)return address(2)創(chuàng)建新的棧幀,清晰的標(biāo)出自己的棧底(3)將最后一個(gè)入?yún)簵#?)計(jì)算java方法的第一個(gè)字節(jié)碼位置(5)將methodOop壓棧(6)將ConstantPoolCache壓棧(7)將局部變量壓棧(8)將第一條字節(jié)碼指令壓棧(9)將操作數(shù)棧棧底地址壓棧

3.slot大小與復(fù)用

虛擬機(jī)通過(guò)索引定位的方式使用局部變量表,索引值的范圍是從 0 開(kāi)始至局部變量表最大的 Slot 數(shù)量。如果訪問(wèn)的是 32 位數(shù)據(jù)類型的變量,索引 n 就代表了使用第 n 個(gè) Slot,如果是 64 位數(shù)據(jù)類型的變量,則說(shuō)明會(huì)同時(shí)使用 n 和 n+1 兩個(gè) Slot。
局部變量表的Slot是可以重用的,方法體中定義的變量作用域并不一定覆蓋整個(gè)方法,如果某個(gè)值已經(jīng)超出作用域時(shí),那么這個(gè)變量對(duì)應(yīng)的Slot可以交給其他變量使用。

4.操作數(shù)棧復(fù)用與深度

每一個(gè)操作數(shù)棧都會(huì)擁有一個(gè)明確的棧深度用于存儲(chǔ)數(shù)值,一個(gè)32bit的數(shù)值可以用一個(gè)單位的棧深度來(lái)存儲(chǔ),而2個(gè)單位的棧深度則可以保存一個(gè)64bit的數(shù)值,當(dāng)然操作數(shù)棧所需的容量大小在編譯期就可以被完全確定下來(lái),并保存在方法的Code屬性中。指令復(fù)用可以減少內(nèi)存空間的使用。

七、類方法解析

1.java方法簽名解析

主要由3部分組成(1)方法標(biāo)識(shí):public、private、static、final、synchronized、native等(2)方法的名稱(3)方法的描述,描述方法的返回值類型和入?yún)⑿畔ⅰ?/p>

2.java方法的code屬性解析

主要包含屬性總長(zhǎng)度、最大棧深度、局部變量表數(shù)量、字節(jié)碼指令。

3.LVT與LVTT

LocalVariableTable屬性用于描述java方法棧幀中局部變量表中的變量與java源代碼定義的變量之間的關(guān)系。LocalVariableTypeTable把記錄的字段描述符的descriptor_index替換成字段特征簽名。

4.method創(chuàng)建

methodOop包含java方法的一切信息,例如方法名、返回值類型、入?yún)ⅰ⒆止?jié)碼指令、棧深、局部變量表、行號(hào)表。HotSpot通過(guò)methodOop將javaclass字節(jié)碼文件中的方法信息存儲(chǔ)到了內(nèi)存中,并且這片內(nèi)存區(qū)域是結(jié)構(gòu)化的,使得可以在jvm運(yùn)行期間方便的訪問(wèn)java方法的各種屬性信息。

5.<clinit>()方法與<init>()方法

Java類中存在用static修飾的靜態(tài)類型字段,或者存在使用static標(biāo)記的代碼塊時(shí),編譯器會(huì)自動(dòng)生成<clint>方法,而當(dāng)java類定義了構(gòu)造函數(shù)或者其非static類成員變來(lái)那個(gè)被賦予了初始值時(shí),編譯器會(huì)自動(dòng)生成<init>方法。

6.使用HSDB查看運(yùn)行時(shí)的字節(jié)碼指令

7.vtable的概念與機(jī)制

Vtable表中保存當(dāng)前類的每一個(gè)方法的指針,jvm會(huì)遍歷vtable中的每一個(gè)指針成員,并根據(jù)指針讀取到對(duì)應(yīng)的method對(duì)象,判斷invokevirtual指令所調(diào)用的方法名稱和簽名與vtable表中指針?biāo)赶虻姆椒ê秃灻欠褚恢拢绻椒ê秃灻耆恢拢瑒t算是找到了invokevirtual所實(shí)際調(diào)用的目標(biāo)方法,jvm定位到目標(biāo)方法的第一條字節(jié)碼指令并開(kāi)始執(zhí)行。

八、執(zhí)行引擎

1.JVM的取指與譯碼機(jī)制

Jvm為java字節(jié)碼指令生成對(duì)應(yīng)的匯編指令,實(shí)現(xiàn)字節(jié)碼指令跳轉(zhuǎn)(取指),jvm需要取出字節(jié)碼指令后,需要將其翻譯成不同的邏輯,然后才能去執(zhí)行。

2.棧頂緩存原理

棧頂緩存的數(shù)據(jù)通過(guò)寄存器來(lái)暫存,降低對(duì)內(nèi)存的讀寫次數(shù)。

3.棧幀重疊技術(shù)

使得兩個(gè)相鄰的棧幀出現(xiàn)一部分重疊,讓前一個(gè)棧幀的操作數(shù)棧與后一個(gè)棧幀的局部變量表區(qū)域部分重疊在一起,這樣在進(jìn)行方法調(diào)用時(shí)就能共用這部分堆棧空間,并且減少額外的參數(shù)復(fù)制。

九、類生命周期

1.類的生命周期

image.png

Java源程序(.java 文件)在經(jīng)過(guò)Java編譯器編譯之后就被轉(zhuǎn)換成Java字節(jié)代碼(.class 文件),java類的生命周期就是指一個(gè)class文件從加載到卸載的全過(guò)程。一個(gè)java類的完整的生命周期會(huì)經(jīng)歷加載、連接、初始化、使用、和卸載五個(gè)階段,當(dāng)然也有在加載或者連接之后沒(méi)有被初始化就直接被使用的情況

2.類加載的內(nèi)部實(shí)現(xiàn)

image.png

3.類的初始化

類的生命周期執(zhí)行完加載和連接之后就開(kāi)始了類的初始化,java虛擬機(jī)執(zhí)行類的初始化語(yǔ)句,為類的靜態(tài)變量賦值。在程序中,類的初始化有兩種途徑(1)在變量的聲明處賦值(2)在靜態(tài)代碼塊處賦值。

4.類加載器的本質(zhì)

Java 中的類加載器是加載Java類文件(*.class)的一個(gè)類。類加載器負(fù)責(zé)從文件系統(tǒng)、網(wǎng)絡(luò)或任何其 它資源中加載類文件。Java中使用的默認(rèn)類加載器有以下三種:Bootstrap , Extension以及System or Application class loader。每個(gè)類加載器都有一個(gè)預(yù)定義的位置,它們?cè)谀抢锛虞d類文件,(1)Bootstrap ClassLoader - JRE/lib/rt.jar(2)Extension ClassLoader - JRE/lib/ext 或者任何指向java.ext.dirs的路徑(3)Application ClassLoader - CLASSPATH環(huán)境變量、-classpath or -cp 命令行選項(xiàng),JAR內(nèi)部清單文件的類路徑屬性
原創(chuàng)文章轉(zhuǎn)載請(qǐng)標(biāo)明出處
更多文章請(qǐng)查看
http://www.canfeng.xyz

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 一:java概述:1,JDK:Java Development Kit,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,687評(píng)論 0 11
  • 第二部分 自動(dòng)內(nèi)存管理機(jī)制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運(yùn)行數(shù)據(jù)區(qū)域 程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,204評(píng)論 0 2
  • 第6章類文件結(jié)構(gòu) 6.1 概述 6.2 無(wú)關(guān)性基石 6.3 Class類文件的結(jié)構(gòu) java虛擬機(jī)不和包括java...
    kennethan閱讀 967評(píng)論 0 2
  • 幾種語(yǔ)言的特性 匯編程序:將匯編語(yǔ)言源程序翻譯成目標(biāo)程序編譯程序:將高級(jí)語(yǔ)言源程序翻譯成目標(biāo)程序解釋程序:將高級(jí)語(yǔ)...
    囊螢映雪的螢閱讀 2,939評(píng)論 1 5
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,716評(píng)論 0 73