• JVM之java对象内存布局(四)


    一、java对象的内存布局

    一个Java对象在内存中包括3个部分:对象头、实例数据和对齐填充

     二、验证hashCode的储存方式

    使用jol工具导入对应包、
            <dependency>
                <groupId>org.openjdk.jol</groupId>
                <artifactId>jol-core</artifactId>
                <version>RELEASE</version>
            </dependency>
    public class Worker {
    private Integer id;
    private String username;
    private String password;

    public Integer getId() {
    return id;
    }

    public void setId(Integer id) {
    this.id = id;
    }

    public String getUsername() {
    return username;
    }

    public void setUsername(String username) {
    this.username = username;
    }

    public String getPassword() {
    return password;
    }

    public void setPassword(String password) {
    this.password = password;
    }

    @Override
    public String toString() {
    return super.toString ();
    }

    public static void printf(Worker p) {
    // 查看对象的整体结构信息
    // JOL工具类
    System.out.println( ClassLayout.parseInstance(p).toPrintable());
    }

    }
    public class Test {
    public static void main(String[] args) {
    Worker work = new Worker();
    //输出对象信息
    System.out.println(work.hashCode());
    System.out.println(work);
    //输出信息
    Worker.printf(work);

    }
    }

    2052001577这个数字是我们的HashCode值,转换成16进制可得7a 4f 0f 29,经过对比。

    由此可得,我们的哈希码使用的大端储存。
    例如: 
    十进制数9877,如果用小端存储表示则为:
    高地址 <- - - - - - - - 低地址
    10010101`[高序字节]` 00100110`[低序字节]`
    用大端存储表示则为:
    高地址 <- - - - - - - - 低地址
    00100110`[低序字节]` 10010101`[高序字节]`
    小端存储:便于数据之间的类型转换,例如:long类型转换为int类型时,高地址部分的数据可以直接截掉。
    大端存储:便于数据类型的符号判断,因为最低地址位数据即为符号位,可以直接判断数据的正负号。

    2.1、Class Pointer 

    引用定位到对象的方式有两种,一种叫句柄池访问,一种叫直接访问

     

     

    区别: 
    句柄池:
    使用句柄访问对象,会在堆中开辟一块内存作为句柄池,句柄中储存了对象实例数据(属性值结构体)的内存地址,访问类型数据的内存地址(类信息,方法类型信息),对象实例数据一般也在heap中开辟,类型数据一般储存在方法区中。
    优点:reference存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要改变。
    缺点:增加了一次指针定位的时间开销。
    直接访问:
    直接指针访问方式指reference中直接储存对象在heap中的内存地址,但对应的类型数据访问地址需要在实例中存储。
    优点:节省了一次指针定位的开销。
    缺点:在对象被移动时(如进行GC后的内存重新排列),reference本身需要被修改。
    指针压缩:
    在32位系统中,类型指针为4字节32位,在64位系统中类型指针为8字节64位,但是JVM会默认的进行指针压缩,所以我们上图输出结果中类型指针也是4字节32位。如果我们关闭指针压缩的话,就可以看到64位的类型指针了,所以我们通常在部署服务时,JVM内存不要超过32G,因为超过32G就无法开启指针压缩了
    关闭指针压缩 : -XX:+UseCompressedOops
    对齐填充 
    没有对齐填充就可能会存在数据跨内存地址区域存储的情况,在没有对齐填充的情况下,内存地址存放情况如下:
    因为处理器只能0x00-0x07,0x08-0x0F这样读取数据,所以当我们想获取这个long型的数据时,处理器必须要读两次内存,第一次(0x00-0x07),第二次(0x08-0x0F),然后将两次的结果才能获得真正的数值。
    那么在有对齐填充的情况下,内存地址存放情况是这样的:
    现在处理器只需要直接一次读取(0x08-0x0F)的内存地址就可以获得我们想要的数据了。对齐填充存在的意义就是为了提高CPU访问数据的效率,这是一种以空间换时间的做法;正如我们所见,虽然访问效率提高了(减少了内存访问次数),但是在0x07处产生了1bit的空间浪费。
  • 相关阅读:
    你不会Python这几个库,不要说你会爬虫
    如何用Python破解验证码,适合新手练手
    2020最新Python入门笔记
    10个超有趣的Python项目,你会哪个?
    Python编程必学规范【新手必学】
    你对Python变量理解到位了没有,80%的人都不知道
    这个男人让你的python爬虫开发效率提升8倍
    Python抖音机器人,论如何在抖音上找到漂亮小姐姐?
    在Python中实现函数重载,60%的人都不会
    2020十大Python面试题,你会几个?
  • 原文地址:https://www.cnblogs.com/xing1/p/15856646.html
Copyright © 2020-2023  润新知