1.對象建立過程:java
①.類加載檢查:當java虛擬機遇到一條new指令時,首先會去檢查該指令的參數可否在常量池中定位到這個類的符號引用,而且檢查這個符號引用表明的類是否已被加載、解析、初始化過,若是沒有,則必須先執行相應的類加載過程。程序員
②.分配內存:類加載檢查完成後,虛擬機將爲新對象分配內存空間,且對象所需內存空間大小在其完成類加載檢查後便可肯定,該過程其實就是在堆中劃分一小部分的肯定大小的空間,用於存儲對象信息。其中分配方式有如下兩種:安全
內存分配的併發問題:性能優化
在建立對象時存在線程安全問題,虛擬機採用兩種方式來保證建立對象的線程安全:架構
CAS鎖+失敗重試:CAS是樂觀鎖的一種實現形式,虛擬機採用CAS+失敗重試來保證更新操做的原子性。
TLAB:爲每個線程預先在Eden區分配一起內存,JVM在給線程中的對象分配內存時,首先在TLAB分配,當對象大於TLAB中的剩餘內存或TLAB的內存已用盡時,再採用上述的CAS進行內存分配。
樂觀鎖:樂觀鎖就是,每次不加鎖而是假設沒有衝突而去完成某項操做,若是由於衝突失敗就重試,直到成功爲止併發
③.初始化零值:內存分配完畢後,虛擬機將該對象分配獲得的內存空間所有設置初始值零(不包含對象頭部分),該操做能夠保證對象的實例字段在代碼中即便不賦予初始值就能夠直接使用。程序能訪問到這些字段的數據類型所對應的零值。分佈式
④.設置對象頭:初始化零值完成後,虛擬機將對象的一些必要信息存放在對象頭中,這些信息包括:例如這個對象是哪一個類的實例、如何才能找到類的元數據信息、對象的哈希嗎、對象的 GC 分代年齡等信息。另外,根據虛擬機當前運行狀態的不一樣,如是否啓用偏向鎖等,對象頭會有不一樣的設置方式。微服務
⑤.執行Init方法:完成上述操做後,java虛擬機即完成了一個對象的建立,可是對於java程序而言,對於該對象的一些定製的內容還未進行,<init>方法中包含了程序員的定製需求和意願,執行完init方法後,對象完成了初始化,此時纔是一個可用對象。高併發
2.對象的內存佈局源碼分析
虛擬機中,對象在內存中的存儲包括三個部分:對象頭、實例數據和對齊填充。
Hotspot虛擬機的對象頭:包括兩部分信息,第一部分用於存儲對象自身的自身運行時數據(哈希嗎、GC分代年齡、鎖狀態標誌等等),另外一部分是類型指針,即對象指向它的類元數據的指針,虛擬機經過這個指針來肯定這個對象是那個類的實例。想學習更多java知識的朋友能夠進羣:874811168 一塊兒學習 還有全套的免費資料領取
實例數據部分:是對象真正存儲的有效信息,也是在程序中所定義的各類類型的字段內容。
對齊填充部分:不是必然存在的,也沒有什麼特別的含義,僅僅起佔位做用。 由於Hotspot虛擬機的自動內存管理系統要求對象起始地址必須是8字節的整數倍,換句話說就是對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的倍數(1倍或2倍),所以,當對象實例數據部分沒有對齊時,就須要經過對齊填充來補全。
3.對象的訪問定位
Java程序經過java棧上的 reference 數據來操做堆上的具體對象。對象的訪問方式有虛擬機實現而定,目前主流的訪問方式有①使用句柄和②直接指針兩種:
①.使用句柄:使用句柄訪問會在java堆中開闢一片區域做爲句柄池,棧中的reference中存儲的就是對象的句柄地址,而句柄中則包含了對象實例數據和類型數據的地址信息。
在java棧中的reference中,包含了須要引用的對象的句柄地址,而後經過句柄地址在句柄池中找到指向對象實例數據和對象類型數據的指針,從而實現引用該對象。
在此我向你們推薦一個架構學習交流羣。交流學習羣號874811168 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多
優勢:引用中存儲的是句柄地址,在對象被移動(垃圾回收時對象移動時很常見的)時,只須要改變句柄中的實例數據指針,而引用中存儲的句柄地址無需改變
缺點:由於引用對象經過兩次指針定位,速度較直接指針訪問慢
②.直接指針:使用直接指針訪問時,reference中存儲的是對象地址:
優勢:節省了一次指針定位的操做,速度較快。