• JVM系列之对象深度探秘


    起笔

    最近的一段时间的精神有点萎靡,导致前两篇文章写的不尽人意,所以就休息了一段时间再来更新文章。

    在这里插入图片描述
    参考书籍:“深入理解java虚拟机”

    个人java知识分享项目gitee地址:Cornucopia

    个人java知识分享项目github地址:Cornucopia

    对象的内存布局

    在这里插入图片描述

    在HotSpot虚拟机中,对象的内存布局分为一下3块区域:

    • 对象头(Header)
    • 实例数据(Instance Data)
    • 对齐填充(Padding)

    对象头中包含了类型指针(Class Pointer),通过改指针能确定对象属于那个类。如果对象是数组对象那么对象头中还会包含数组的长度。

    对象头(Header)

    在HostSpot虚拟机对象的对象头部分包含了两类信息:

    • 用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为32bit和64bit(8byte),官方称它为“Mark World”

    • 对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针(Class Pointer),Java虚拟机通过这个指针来确定该对象是那个类的实例。此外,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是如果数组的长度是不确定,将无法通过元数据的信息推断出数组的大小。因此,如果对象是一个数组,那么对象头中还必须有一块用于记录数组长度的数组,也就是上图中的Data Length。

    实例数据(Instance Data)

    实例数据是对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来。

    对齐填充(Padding)

    对齐填充并不是必然存在的,也没有特别的含义,它仅仅起占位符的作用。那为什么要有这么一段数据是因为HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8byte的整数倍,换句话说就是任何对象的大小都必须是8字节的整数倍。对象头部分已经被精心设计成正好是8byte的倍数(1倍或者是2倍),因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。

    分析案例

    我们已经有对象内存布局的理论知识,现在,我们通过一个案例来加深一下印象:

    案例:

    new user();在内存中一共占多少个字节?

    public class user {
       private String name;
       private int age;
    }
    
    • 1
    • 2
    • 3
    • 4

    解析

    在开始之前,我们需要创建一个maven项目,然后引入JOL工具包

    <dependency>
        <groupId>org.openjdk.jol</groupId>
        <artifactId>jol-core</artifactId>
        <version>0.16</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    执行代码:

    public class ObjectTest {
        public static void main(String[] args) {
            System.out.println(ClassLayout.parseInstance(new user()).toPrintable());
        }
        static class user {
            private String name;
            private int age;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    JVM参数:

    打印被设置的参数 : -XX:+PrintCommandLineFlags

    结果:

    JVM参数打印:

    -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC 
    
    • 1

    终端输出内容:
    在这里插入图片描述

    我们来分析一下,首先看jvm参数中的XX:+UseCompressedClassPointers ,我们知道它开启了指针压缩(也就是会压缩ClassPointer的内存大小,从8byte->4byte),那么,按照上面我们掌握的理论知识,一个对象内存包含三个部分,对象头为固定的8byte,ClassPointer如果开启了指针压缩则是4byte,Instance Data这里user中包含了一个int对象占4byte,String是一个引用对象固定占4byte,也就是Instance Data总共占8byte,由于Padding是占位符,我们先不分析,这里对象头和对象数据总共占 8+4+8=20,这里20不是8的倍数,由于jvm的内存管理的限制,这里jvm会将padding按找距离20byte最少的8的倍数进行填充,也就是24byte,padding就是4byte(即图中的 (object alignment gap) 所占的byte大小)。

  • 相关阅读:
    分类网络-类别不均衡问题之FocalLoss
    HTML基础用法
    2311vim极语言加高亮
    mysql的mysql_store_result函数调用问题(C的API)
    React 中 useEffect
    ASP.NET CORE 用户登录失败达到一定次数如何锁住账户
    多重背包-单调队列优化
    ThreadLocal:线程中的全局变量
    leetcode 399 除法求值
    ArcGIS Pro脚本工具(6)——修复CAD图层数据源
  • 原文地址:https://blog.csdn.net/a_ittle_pan/article/details/125459788