JVM學(xué)習(xí)筆記(第二章)

前言

對JVM第二章的知識點進行總結(jié),同時方便自己以后的回顧。

Java虛擬機的多線程

通過線程輪流切換并分配處理器執(zhí)行時間的方式實現(xiàn)

程序計數(shù)器

如果執(zhí)行的是Java方法,計器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令的地址,字節(jié)碼解釋器通過改變計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基本功能都需要依賴這個計數(shù)器來完成。

線程私有

各個線程之間計數(shù)器互不影響,獨立存儲。

OutOfMemoryError:無,唯一

Java虛擬機棧

生命周期和線程相同,描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。

線程私有
局部變量表

存放編譯期復(fù)制的各種基本數(shù)據(jù)類型(boolean、byte、char、short、int、float、long<2>、double<2>)、對象引用(可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔?,也可能是指向一個代表對象的句柄或其他與此對象相關(guān)的位置)、returnAdress類型(指向一條字節(jié)碼指令的地址)

StackOverflowError

當(dāng)線程請求的棧深度大于虛擬機所允許的深度。

OutOfMemoryError

如果虛擬機可以動態(tài)擴展。當(dāng)擴展時無法申請到足夠的內(nèi)存。

本地方法棧

與虛擬機棧的作用非常相似,不同在于虛擬機棧為Java服務(wù),本地方法棧為Native方法服務(wù)。

Java堆

在虛擬機啟動時創(chuàng)建,所有對象實例以及數(shù)組都要在堆上分配(但隨著JIT編譯器和逃逸分析技術(shù)的成熟,所有對象都要在分配在堆上變得不那么絕對),是垃圾收集器管理的主要區(qū)域

線程共享
OutOfMemoryError

當(dāng)堆中沒有內(nèi)存完成實例分配,并且堆也無法再擴展時。

方法區(qū)

用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。

注意點:HotSpt虛擬機把GC分代收集擴展至方法區(qū),即是用永久代來實現(xiàn)方法區(qū),對于其他的虛擬機來說不存在永久代的概念。

特點:除了和Java堆一樣不需要連續(xù)的內(nèi)存空間和可以選擇固定大小或可擴展外,還可以選擇不實現(xiàn)垃圾收集。相對而言,垃圾收集行為在這個區(qū)域比較少出現(xiàn),這區(qū)域的內(nèi)存回收目標主要是針對常量池的回收和對類型的卸載,但是垃圾收集的效果不好,尤其是類型卸載。

OutOfMemoryError

當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時。

線程共享

運行時常量池

是方法區(qū)的一部分,用于存放Class文件中的常量池在編譯期生成的各種字面量和符號引用。

特點:運行時常量池具有動態(tài)性,并不是預(yù)置入Class文件中常量池的內(nèi)容才能進入方法區(qū)的運行時常量池,運行期間也可能將新的常量放入池中,比如String類的intern()方法。

注意點:JDK1.7之前,String的intern()方法會把首次遇到的字符串實例復(fù)制到永久代中(方法區(qū)稱為永久代,方法區(qū)的運行時常量池),返回的也是永久代中這個字符串實例的引用,如果不是該字符串不是首次出現(xiàn),則直接返回已存在字符串實例的引用。JDK1.7之后,String的intern()方法不會在復(fù)制首次遇到的實例,而是在常量池中記錄首次出現(xiàn)的實例引用,如果不是該字符串不是首次出現(xiàn),則直接返回已存在字符串實例的引用。

OutOfMemoryError

當(dāng)常量池?zé)o法再申請到內(nèi)存時。

直接內(nèi)存

使用Native函數(shù)庫直接分配堆外內(nèi)存,然后通過存儲在Java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作。

注意點:直接內(nèi)存更適合在內(nèi)存申請次數(shù)較少,但讀寫操作較頻繁的場景。

OutOfMemoryError

對象的創(chuàng)建

(1) 首先檢查new指令的參數(shù)能否在常量池中定位到一個類的符號引用。

(2) 檢查這個符號引用代表的類是否已被加載、解析和初始化過。如果沒有,那必須先執(zhí)行相應(yīng)的類加載過程。

(3) 虛擬機為新生的對象分配內(nèi)存,對象所需的內(nèi)存大小在類加載完成后便可完全確定。

(4) 內(nèi)存分配完成后,虛擬機會把分配到的內(nèi)存空間都初始化為零值(不包括對象頭),保證了對象實例字段在Java代碼中可以不賦初值就可以直接使用。

(5) 虛擬機要對對象進行必要的設(shè)置,例如這個對象是哪個類的實例、如何才能找到類的元數(shù)據(jù)信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息存放在對象的對象頭中。

(6) 執(zhí)行<init>方法,把對象按照程序員的意愿進行初始化。

堆內(nèi)存分配規(guī)則

指針碰撞--假設(shè)java堆中的內(nèi)存是絕對規(guī)整的,所有用過的內(nèi)存放在一邊,空閑的內(nèi)存放在另一邊,使用指針作為分界點的指示器。那么在分配內(nèi)存時,只需要指針向空閑空間的方向移動對象大小相等的距離即可。

空閑列表--如果java堆的內(nèi)存并不是規(guī)整的,虛擬機需要維護一個列表,記錄上哪些內(nèi)存塊是可用的,在分配內(nèi)存時從列表中找到一塊足夠大的空間劃分給對象實例,并更新列表上的記錄。

并發(fā)

(1) 對分配內(nèi)存空間的動作進行同步處理——實際上虛擬機采用CAS配上失敗重試的方式保證更新操作的原子性。

(2) 把內(nèi)存分配的動作按照線程劃分在不同的空間之中進行,即每個線程在Java堆中預(yù)先分配一小塊內(nèi)存,稱為本地線程分配緩沖(Thread Local Allocation Buffer,TLAB)。那個線程要分配內(nèi)存,就在哪個線程的TLAB上分配,只有TLAB用完并分配新的TLAB是,才需要同步鎖定。

對象的內(nèi)存布局

對象頭

第一部分:用于存儲對象自身的運行時數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標記、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數(shù)據(jù)的長度在32位和64位的虛擬機上中分別為32bit和64bit,官方稱它為“Mark Word”。Mark Word是非固定的數(shù)據(jù)結(jié)構(gòu),它會根據(jù)自己的狀態(tài)復(fù)用自己的存儲空間。

image

第二部分:類型指針,即對象指向它的類元數(shù)據(jù)的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。另外,如果對象是一個Java數(shù)組,那在對象頭中還必須包括一塊用于記錄數(shù)組長度的數(shù)據(jù),因為虛擬機可以通過普通Java對象的元數(shù)據(jù)信息確定Java對象的大小,但是無法通過數(shù)組的元數(shù)據(jù)確定數(shù)組的大小。

注意:并不是所有的虛擬機實現(xiàn)都必須在對象數(shù)據(jù)上保留類型指針,換句話說,查找對象的元數(shù)據(jù)信息并不一定要經(jīng)過對象本身。<2.3.3>

實例數(shù)據(jù)

存儲程序代碼中所定義的各種類型的字段內(nèi)容。無論是從父類繼承下來的,還是在子類中定義的,都會被記錄起來。

對齊填充

對齊填充并不是必然存在的,也沒有特變的含義,僅僅起到占位符的作用。由于HotSpot VM的自動內(nèi)存管理系統(tǒng)要求對象的起始地址必須是8個字節(jié)的倍數(shù),所以對象所占的內(nèi)存如果不是8個字節(jié)的倍數(shù),就需要通過對齊填充來補全。

對象的訪問定位

使用句柄

在Java堆中劃分出一塊內(nèi)存作為句柄池,reference中的存儲的就是對象的句柄地址,而句柄中包含了對象實例數(shù)據(jù)與類型數(shù)據(jù)各自的具體地址信息。

image

優(yōu)勢:reference中存儲的是穩(wěn)定的句柄地址,在對象被移動時只會改變句柄池的實例數(shù)據(jù)指針。

直接指針訪問

reference中存儲對象的地址

image

優(yōu)勢:速度更快,節(jié)省了一次指針定位的時間開銷。·

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容