先作个铺垫: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没有影响。固然,这里我只是实验了一个,这个结论不是很严谨。