对象实例化指针_JVM第三课:一文讲透对象的内存布局和访问方式
對象的內(nèi)存布局和訪問定位
對象的實(shí)例化
對象的創(chuàng)建方式
new
Class的newInstance方法
Class> aClass = Class.forName("com.mu.ConstructorDemo");ConstructorDemo o = (ConstructorDemo)aClass.newInstance();
Constructor的newInstance方法,可以放參數(shù),調(diào)用有參構(gòu)造
Constructor constructor = ConstructorDemo.class.getConstructor();ConstructorDemo constructorDemo = constructor.newInstance();
Clone:不調(diào)用構(gòu)造方法,當(dāng)前類實(shí)現(xiàn)Cloneable接口
反序列化
創(chuàng)建對象的步驟
判斷對象對應(yīng)的類是否加載,鏈接,初始化
虛擬機(jī)遇到一個(gè)new指令,首先去檢查這個(gè)指令的參數(shù)能否在Metaspace的常量池中定位到這個(gè)類的符號引用,并且檢查這個(gè)符號引用代表的類是否已經(jīng)被加載,解析和初始化。
如果沒有,那么在雙親委派模式下,使用當(dāng)前的類加載器,以ClassLoader+包名+類名為key進(jìn)行查找對應(yīng)的.class文件,如果沒有找到文件,則拋出ClassNotFoundException異常,如果找到,則進(jìn)行類加載,并生成對應(yīng)的Class類對象
為對象分配內(nèi)存
首先計(jì)算對象占用空間大小,接著在堆中劃分一塊內(nèi)存給新對象
如果實(shí)例成員變量是引用變量,僅分配引用變量即可,即4個(gè)字節(jié)大小
如果內(nèi)存規(guī)整,使用指針碰撞
所有用過的內(nèi)存在一邊,空閑的內(nèi)存在另一邊,中間放著一個(gè)指針作為分界點(diǎn)的指示器,分配內(nèi)存就僅僅把指針向空閑那邊挪動(dòng)一段與對象大小相等的距離
有壓縮算法和整理功能的垃圾回收器,采用指針碰撞的方式分配內(nèi)存
如果內(nèi)存不規(guī)整,虛擬機(jī)維護(hù)一個(gè)列表,使用空閑列表分配(CMS垃圾收集器)
意思是虛擬機(jī)維護(hù)一個(gè)列表,記錄那些內(nèi)存塊是可用的,再分配的時(shí)候從列表中找到一塊足夠大的空間劃分給對象實(shí)例,并更新列表上的內(nèi)容,這種分配方式稱為“空閑列表”
處理并發(fā)安全問題
創(chuàng)建對象是非常頻繁的操作,虛擬機(jī)需要解決并發(fā)安全問題,兩種方式:
CAS(Compare And Swap)失敗重試,區(qū)域加鎖,保證指針更新操作的原子性
TLAB:本地線程緩沖區(qū)
初始化分配到的空間
內(nèi)存分配結(jié)束,虛擬機(jī)將分配到的內(nèi)存都初始化成零值(不包括對象頭),這一步保證了對象的實(shí)例字段在Java代碼中可以不用賦值就可以使用,程序訪問的都是這些字段的零值
設(shè)置對象頭
將對象的所屬類(類的元數(shù)據(jù)信息),對象的HashCode和對象的GC信息,鎖信息等存儲(chǔ)在對象的對象頭中,這一塊具體有JVM實(shí)現(xiàn)
執(zhí)行init方法進(jìn)行初始化
顯式賦值
對象的內(nèi)存布局
對象頭
包含兩部分:
如果是數(shù)組,還需要記錄數(shù)組的長度
運(yùn)行時(shí)元數(shù)據(jù)
哈希值,GC分代年齡,鎖狀態(tài)標(biāo)志,線程持有的鎖,偏向線程ID,偏向時(shí)間戳
類型指針
指向類元數(shù)據(jù),確定該對象所屬的類型
實(shí)例數(shù)據(jù)
它是對象真正存儲(chǔ)有效信息,包括程序代碼中定義的各種類型的字段(包括從父類繼承下來的和自己擁有的)
相同寬度的字段分配在一起(比如4個(gè)字節(jié)的數(shù)據(jù)在一起)
父類定義的變量會(huì)出現(xiàn)在子類之前
如果CompactFields參數(shù)為true(默認(rèn)是true),子類的窄變量可能插入到父類的變量的間隙
對齊填充
僅僅起到占位符的作用
package com.mu;public class Customer {
public int id = 1001;
String name;
Account acct;
{
name = "匿名客戶";
}
public Customer(){
acct = new Account();
}
public static void main(String[] args) {
Customer cust = new Customer();
}
}
class Account{
}
實(shí)際分配圖如下:
對象的訪問定位:
訪問對象的方式有兩種:句柄和直接指針
句柄訪問
圖示:
有一個(gè)句柄池的概念,棧指向句柄池,句柄池保存對象的實(shí)例數(shù)據(jù)和對象的類型數(shù)據(jù)
優(yōu)點(diǎn)是棧到句柄池的地址不會(huì)改變,reference存儲(chǔ)的是穩(wěn)定的句柄地址,在對象被移動(dòng)時(shí)(垃圾回收時(shí))只會(huì)改變句柄中到實(shí)例數(shù)據(jù)的指針
直接指針(Hotspot采用直接指針)
reference存儲(chǔ)的就是對象的引用地址,最大的好處就是速度快,節(jié)省了一次指針定位的開銷,
總結(jié)
以上是生活随笔為你收集整理的对象实例化指针_JVM第三课:一文讲透对象的内存布局和访问方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nginx之为已安装nginx动态添加模
- 下一篇: 如何把一些不同类型的数据混合存入一片内存