• java对象的存储结构和指针压缩学习


    HotSpot虚拟机里,对象在堆内存中的存储不惧可以划分为三个部分:

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

    对象头包含了Mark Word(一定存在),元数据指针(一定存在),数组size(如果这个对象是个数组对象的话)。

    实例数据:类元信息中定义的变量数据

    对齐填充可能存在的部分,同对象头一样,为了8字节对齐的无实际意义填充部分。

    64位虚拟机来说,低于32G内存,默认开启指针压缩,那么堆中的对象是这样子的。

    可以使用jol包来观察对象的存储结构,引入pom文件
    <dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.10</version>
    </dependency>

    1)查看对象内部信息: ClassLayout.parseInstance(obj).toPrintable()

    2)查看对象占用空间总大小:GraphLayout.parseInstance(obj).totalSize() 一个空的Object对象,64位虚拟机打开指针压缩(默认开启或者VM -options设置下  -XX:+UseCompressedOops开启)

    3)测试

    package com.test.demo.test.jvm;
    
    import org.openjdk.jol.info.ClassLayout;
    import org.openjdk.jol.info.GraphLayout;
    
    /**
     * @program: demo
     * @description: 查看对象内存 空对象一般16b(没有普通属性的类生成的对象)
     * -XX:+UseCompressedOops开启指针压缩(默认) oop对象指针
     * -XX:-UseCompressedOops关闭指针压缩
     * 指针压缩的原理:
     * 指针不再表示对象在内存中的精确位置,而是表示偏移量。这意味着32位的指针可以引用40亿个对象,
     * 而不是40亿个字节。最终,也就是说内存增长到32GB的物理内存,也可以用32位的指针表示。也就是说,我们只需要
     * 知道JVM内存的开始位置,知道偏移量,就可以算出我想要找的实际物理位置。
    
    ---------------对象头区域-----------实例数据区域---------对齐填充区域(保证8的倍数)
          markword( 32位 4byte ---64位 8byte)
          class指针(开启指针压缩 4byte 关闭 8byte)
          数组对象(开启指针压缩 4byte 关闭 8byte)
     * @author: zhugaopo
     * @slogan: 致敬大师、致敬未来的你.
     * @create: 2020-07-16 10:17
     */
    public class CountObjectSize {
        int a = 10; 
        int b = 20; 
        String[] aa =new String[]{"a","b","c"};
    
        public static void main(String[] args) {
            Object object = new Object();
            String s1 = ClassLayout.parseInstance(object).toPrintable();
            System.out.println("空对象"+ s1);
            //空Object 开启指针压缩:  markword 8bytes + class地址 4bytes + 成员变量 0bytes + 对齐填充 4bytes = 16bytes
            //空Object 关闭指针压缩:  markword 8bytes + class地址 8bytes + 成员变量 0bytes + 对齐填充 0bytes = 16bytes
            CountObjectSize countObjectSize = new CountObjectSize();
            String s = ClassLayout.parseInstance(countObjectSize).toPrintable();
            System.out.println(s);
            //非空Object 开启指针压缩:  markword 8bytes + class地址 4bytes + 成员变量 4 + 4 + 4 bytes + 对齐填充 0bytes = 24bytes
            //非空Object 关闭指针压缩:  markword 8bytes + class地址 8bytes + 成员变量 4 + 4 + 8 bytes + 对齐填充 0bytes = 32bytes
    
            //数组对象在关闭指针压缩的情况下 8byte 开启4byte
            //开启指针压缩,提升jvm运行效率
            long l = GraphLayout.parseInstance(countObjectSize).totalSize();
            System.out.println(l);
        }
    }

    输出:

    1、空对象开启/关闭指针压缩:

    空Object 开启指针压缩:  markword 8bytes + class指针 4bytes + 成员变量 0bytes + 对齐填充 4bytes = 16bytes

    空Object 关闭指针压缩:  markword 8bytes + class指针 8bytes + 成员变量 0bytes + 对齐填充 0bytes = 16bytes

    2、包含数组的对象开启/关闭指针压缩:

    
    
    开启指针压缩:  markword 8bytes + class指针 4bytes + 成员变量 0bytes + 对齐填充 4bytes = 16bytes

     关闭指针压缩: markword 8bytes + class指针 8bytes + 成员变量 0bytes + 对齐填充 0bytes = 16bytes

     
    
    
  • 相关阅读:
    jQuery基础
    前端武器库之DOM练习
    前端逼死强迫症之DOM
    前端武器库系列之html后台管理页面布局
    前端逼死强迫症系列之javascript续集
    初识elasticsearch_2(查询和整合springboot)
    初识elasticsearch_1(基本概念和基本操作)
    springboot整合redis(注解形式)
    springsecurity实战
    浅谈JavaSript中的this
  • 原文地址:https://www.cnblogs.com/godpo/p/13321604.html
Copyright © 2020-2023  润新知