前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK之JVM中Java对象的头部占多少byte

JDK之JVM中Java对象的头部占多少byte

作者头像
克虏伯
发布2019-04-15 10:57:06
1.2K0
发布2019-04-15 10:57:06
举报

    先做个铺垫:

  •         在32位机器上word size是32bits,CPU一次性处理32bits,在64位机器上word size是64bits,CPU一次性处理64bits。
  •         Data bus size, instruction size, address size are usually multiples of the word size,这句参考自Stackoverflow。   

1. Stackoverflow上看到的Java对象头部mark word和kclass pointer的大小

    从Stackoverflow上看到,Java对象头部有一个mark word和一个klass pointer,

  • mark word:32bits architectures上,mark word占32bits,64bits architectures上,mark word占64bits;
  •     kclass pointer:32bits architectures上,kclass pointer占32bits,64bits architectures上,kclass pointer占64bits,但也可能是32bits,原话是这样"the klass pointer has word size on 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"。

2. 上面说的是否正确呢,我本地JVM上对象头部的mark word和kclass pointer也是如上述那样吗?

    我们来验证下。注意:我电脑上装的JDK1.8,64位的

2.1 验证Java对象的头部占用byte数

    如下:

List-1

代码语言:javascript
复制
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-2

代码语言:javascript
复制
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源码运行的结果如下图,

                                                        图1 List-2中main运行的结果

    图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位的。

2.2 验证Java数组对象的头部占用byte数

List-3 验证数组的情况

代码语言:javascript
复制
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对象头部是有区别的。

3.分析Java的伪分享时考虑对象头部占的byte

    我们在做伪分享分析,进行填充数据时,要考虑对象头部,最好自己测试下自己系统JVM上对象头部占多少bytes,不要照搬别人的数据,因为很有可能别人使用的JVM和你的不一样。

    下面我们来分析俩种情况。

List-4

代码语言:javascript
复制
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

代码语言:javascript
复制
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外,还有其它情况的。所以不要轻易的照搬别人的数据,最好是自己测试下。

4.类中的get/set/contructor对对象占多少byte有影响吗

    一般情况下,Java类不仅有属性,也有方法。经过上面的实验,证实类属性对对象占多少byte有影响,那么类的方法数量是否多对象占byte有影响呢?我们来做实验验证下。

    我们给List-5中的类,加上get/set/constructor,如下List-6

List-6 类A加上get/set/contructor

代码语言:javascript
复制
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没有影响。当然,这里我只是实验了一个,这个结论不是很严谨。

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018/06/30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. Stackoverflow上看到的Java对象头部mark word和kclass pointer的大小
  • 2. 上面说的是否正确呢,我本地JVM上对象头部的mark word和kclass pointer也是如上述那样吗?
    • 2.1 验证Java对象的头部占用byte数
      • 2.2 验证Java数组对象的头部占用byte数
      • 3.分析Java的伪分享时考虑对象头部占的byte
      • 4.类中的get/set/contructor对对象占多少byte有影响吗
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档