本文將學習對象是如何建立的,對象的內存佈局,以及如何定位訪問一個對象。java
當虛擬機碰到一個new指令時,首先檢查指令參數可否在常量池中定位一個類的符號引用,而且檢查該符號引用對應的類是否已經被加載,解析和初始化。當一切都肯定完成後,JVM就會爲其分配內存(須要分配的內存大小在如今就已經肯定,在 下面 中詳細講述)。算法
對象的內存分配方式分爲如下兩種:jvm
以上兩種方式採起哪一種,取決於 Java 堆是否工整,而堆是否工整又取決於垃圾回收算法是否具備整理功能。佈局
前面說到對象在建立時就已經肯定了內存大小,那麼 JVM 是怎麼肯定對象的大小呢?對象在內存中又是如何存儲的呢?學習
在 JVM 中 Java 的對象模型分爲如下3塊,對象頭,實例數據,對齊填充,下面就讓咱們來分別介紹一下。線程
對象頭的數據包括兩部分。一部分是用於存儲自身運行時數據,這部分數據被官方稱爲「Mark World」。其中存儲數據包括Hashcode、GC 分代年齡、鎖狀態標誌、線程持有鎖、偏向線程ID、偏向時間戳等等。指針
對象頭的另一部分是 類型指針,即對象指向其類元數據的指針。經過這個指針,咱們就能夠知道該實例屬於哪一個類。code
實例數據就是對象真正存儲的有效信息,也就是代碼中定義的各類類型的字段內容,不管是父類的仍是子類的,都須要記錄下來。其存儲順序受到虛擬機分配策略和定義順序影響。對象
對象填充不是必要數據。在模型中只是起到佔位符的做用。由於 HotSpot 要求對象起始地址必須是8的整數倍,這樣在實例數據達不到要求的時候,就須要經過對齊填充來補齊。blog
對象訪問的方式是經過引用來定位、訪問。但 JVM 規範並無強制要求該經過何種方式使用引用,所以具體實現仍是要依賴與具體虛擬機類型。
不過目前的主流訪問方式就是如下兩種。
使用這種方式來訪問的優勢是穩定,例如在 GC 後,實例數據須要移動,那麼只須要修改句柄池中的內容便可,reference 指向的是穩定的位置,缺點是這種方式須要二次定位,速度較慢。
使用這種方式的優勢是訪問實例數據快,由於 reference 指向直接的對象,省去了一次內存定位開銷。但缺點就是不夠穩定,在對象移動後,reference 也須要修改值。
具體採用何種,不一樣的虛擬機有不一樣的實現,由於二者各有千秋,並無強烈的優缺點,所以不一樣狀況不一樣處理便可。
在本文中介紹了對象的本質模型是什麼,以及對象是如何建立和訪問使用的,與上文的 JVM 內存模型結合來看,可讓咱們瞭解內存泄露產生的緣由,有助於高效地理解使用 Java 的自動內存管理機制。
文章在公衆號「iceWang」第一手更新,有興趣的朋友能夠關注公衆號,第一時間看到筆者分享的各項知識點。謝謝!筆芯!
本系列文章主要借鑑自《深刻分析 Java Web 技術內幕》和《深刻理解 Java 虛擬機-JVM 高級特性與最佳實踐》。