先作個鋪墊:java
從Stackoverflow上看到,Java對象頭部有一個mark word和一個klass pointer,數組
32 bit
architectures. On 64 bit
architectures the klass pointer either has word size, but can also have 4 byte
if the heap addresses can be encoded in these 4 bytes
"。咱們來驗證下。注意:我電腦上裝的JDK1.8,64位的bash
以下:ide
List-1oop
mjduan@mjduandeMacBook-Pro:/tmp % java -version java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
我用openJDK的jol來查看對象的layout,源碼以下,直接運行main方法,測試
List-2ui
package com.mjduan.project.openjdk_jol_example; import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.vm.VM; /** * @author dmj1161859184@126.com mjduan 2018-06-29 17:10 * @version 1.0 * @since 1.0 */ public class JOLSample_12_ThinLocking { public static void main(String[] args) throws Exception { System.out.println(VM.current().details()); final A a = new A(); ClassLayout layout = ClassLayout.parseInstance(a); } public static class A { // no fields } }
List-2源碼運行的結果以下圖,this
圖1 List-2中main運行的結果spa
圖1中,第一個紅框中的就是對象頭部的mark word,佔了8bytes,即64bits,這個也能夠直接參考openJDK8的hotspot的markOop.hpp。以後4bytes,即第二個紅框,是kclass pointer佔的,即4bits。操作系統
圖1中offset從12開始的4個bytes,沒有被使用到。圖1中對象頭部的mark word和kclass pointer佔了12bytes,可是最後JVM卻認爲它佔了16bytes,爲何呢,這和內存的aligment有關,因此加了最後的4bytes,讓總的byte數是8的倍數(這裏的8表示8bytes,即64bits),爲何是64bits,由於個人機器是64位的,個人JVM是64位的。
List-3 驗證數組的狀況
import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.vm.VM; /** * @author dmj1161859184@126.com mjduan 2018-06-29 13:16 * @version 1.0 * @since 1.0 */ public class JOLSample_11_ClassWord { public static void main(String[] args) throws Exception { System.out.println(VM.current().details()); A[] as = new A[2]; System.out.println(ClassLayout.parseInstance(new A[2]).toPrintable()); } public static class A { // no fields } }
List-3的運行結果以下圖2
圖2 List-3的運行結果
圖2的說明:第一個紅框和第二個紅框分別是mark word和kclass pointer,它們分別佔8bytes和4bytes,以後的4bytes用來表示數組長度。第三個紅框下面的8bytes是什麼呢?List-3源碼中的,咱們的數組new A[2]的長度是2,每一個下標處佔4bytes,這個相似C語言中的指針。
因此能夠看到數組和普通的Java對象頭部是有區別的。
咱們在作僞分享分析,進行填充數據時,要考慮對象頭部,最好本身測試下本身系統JVM上對象頭部佔多少bytes,不要照搬別人的數據,由於頗有可能別人使用的JVM和你的不同。
下面咱們來分析倆種狀況。
List-4
import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.vm.VM; /** * @author dmj1161859184@126.com mjduan 2018-06-29 12:34 * @version 1.0 * @since 1.0 */ public class JOLSample_01_Basic { public static void main(String[] args) throws Exception { System.out.println(VM.current().details()); ClassLayout layout = ClassLayout.parseInstance(new A()); System.out.println(layout.toPrintable()); } public static class A { boolean f; } }
List-4的運行結果下圖3所示:
圖3 List-4的運行結果
List-5
import org.openjdk.jol.info.ClassLayout; import org.openjdk.jol.vm.VM; /** * @author dmj1161859184@126.com mjduan 2018-06-29 12:36 * @version 1.0 * @since 1.0 */ public class JOLSample_02_Alignment { public static void main(String[] args) throws Exception { System.out.println(VM.current().details()); ClassLayout layout = ClassLayout.parseInstance(new A()); System.out.println(layout.toPrintable()); } public static class A { long f; } }
List-5的運行結果以下圖4所示:
圖4 List-5的運行結果
咱們來對比下圖3和圖4的結果,圖3中顯示對象佔了16bytes,可是圖4中顯示對象佔了24bytes。是什麼致使結果變化的呢,注意看類A中的屬性,由boolean類型變爲了long,在long的狀況下,佔8bytes,不能使用12~15這4個bytes,因此給long類型的屬性f分配的是offset從16開始的8個bytes。這是因爲操做系統在內存管理方面的aliment致使的。
通過上面的這麼多分析,咱們應該發現要想肯定對象佔有的byte數,仍是難的。JVM中對象佔用byte的狀況除圖3和圖4外,還有其它狀況的。因此不要輕易的照搬別人的數據,最好是本身測試下。
通常狀況下,Java類不只有屬性,也有方法。通過上面的實驗,證明類屬性對對象佔多少byte有影響,那麼類的方法數量是否多對象佔byte有影響呢?咱們來作實驗驗證下。
咱們給List-5中的類,加上get/set/constructor,以下List-6
List-6 類A加上get/set/contructor
public class A { long f; public A() { } public long getF() { return f; } public void setF(long f) { this.f = f; } @Override public String toString() { return "A{" + "f=" + f + '}'; } }
再用List-5的main方法代碼,執行下,看結果:
圖5 List-6的運行結果
圖5中的結果與圖4中的結果同樣,說明類的方法數量,對Java對象佔多少byte沒有影響。固然,這裏我只是實驗了一個,這個結論不是很嚴謹。