您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關如何解密Java對象,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
在Java程序運行過程中時時刻刻都有對象被創建出來,對象的創建方式有很多種,最常見的就是new,其次還有clone和反序列化。下面我們一起來解密對象的創建、內存布局以及如何定位一個對象。
當我們在創建對象時,首先會檢查創建對象的類能否在常量池中定位到符號引用,并檢查符號引用代表的類是否被加載、解析和初始化過,如果沒有則必須執行相應的類加載過程(這個后面也會單獨寫一篇文章講解)。
對象創建的過程大約有以下幾步:
為對象分配內存本質上就是從Java堆中劃分出一塊固定大小的內存給Java對象使用。對象內存分配主要有兩種:
具體使用哪種方式取決于堆內存是否工整,堆內存是否工整本質又取決于垃圾回收器是否帶有壓縮整理功能。
指針碰撞的分配方式用于在內存工整的堆中進行對象分配,所有被使用的內存放在一邊,未被使用的在另一邊,中間放著一個指針作為分界點的指示器,當為對象分配內存時,只需要將指針往未被使用的一邊挪動與對象相等大小的距離就可以。
空閑列表適合在不規整的內存中為對象分配內存,虛擬機為了知道哪些內存區域可用,必須維護一個列表,當進行內存分配時,則在列表中選取一個足夠大的空間劃分給對象使用。
對象分配在虛擬機中的分配并不是線程安全的,為了解決這個問題,主要有兩種解決方法:
對象在內存中的布局主要有三塊:
對象頭主要用來存儲兩塊信息:
對象自身運行時的數據主要包括:哈希碼、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID、偏向時間戳等。這部分數據的長度在32位和64位的虛擬機(未開啟壓縮指針)中分別為32位和64位。
存儲內容 | 標志位 | 狀態 |
---|---|---|
對象哈希碼、對象分代年齡 | 01 | 未鎖定 |
指向鎖記錄的指針 | 00 | 輕量級鎖定 |
指向重量級鎖的指針 | 10 | 膨脹(重量級鎖定) |
空,不需要記錄信息 | 11 | GC標記 |
偏向線程ID、偏向時間戳、對象分代年齡 | 01 | 可偏向 |
類型指針可以用來確定這個對象是哪個類的實例,但虛擬機的實現不是必須在對象上保留類型指針。
實例數據是對象真正存儲的有效信息,就是代碼中各種類型字段的內容,無論是從父類還是子類中定義的,內容存儲的順序會受到虛擬機分配策略參數和字段在Java源碼中定義順序的影響。 但是相同寬度的字段會分配到一起,在這個前提條件下,子類較窄的變量會插到父類變量的空隙之中。
對齊填充并不是必然存在,由于虛擬機的內存管理要求對象其實地址必須是8字節的整數倍,也就是對象大小必須是8字節的整數倍,因此當對象實例不是8字節的整數倍大小時,需要通過對齊填充補全。
對象建立以后我們需要使用它,我們可以通過Java棧上的reference來操作堆上的具體對象,但是如何通過reference來找到具體的對象則是需要我們去解決的,目前主要有兩種方式:
下圖是采用句柄的方式去訪問對象
下圖是采用直接指針的方式去訪問對象
通過上述兩種圖的對比,我們可以看出句柄的優勢在于棧中的reference存儲的內容是穩定的句柄地址,不會因為對象的移動而改變,但訪問會遜于直接指針,因為多了一次指針定位的時間開銷。
直接指針的訪問方式的最大好處就是速度快,節省了一次指針定位的時間開銷。
關于如何解密Java對象就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。