对象存储布局,对象如何定位,对象如何分配

普通对象

普通对象 new Object();任意一个对象,由四块构成。

名称解释
markword标记字 (ash code、对象年龄、GC标志位、锁状态等信息)
class pointer类型指针,比如你new T(),那么指向的就是T.class,用于存放方法区Class对象的地址,虚拟机通过此地址确定该对象是属于哪一个类。
instance data实例数据,比如类中的int a = 8;用于存放实例域,包括父类的成员属性
padding对齐,64位二进制对齐,相当于8字节对齐。意思是前面三点加起来不能被8整除,那么需要进行补位,补到能被8整除,比如前面三点加起来为25,那么需要补到被8整除,就需要加7位,达到32位。这就是对齐

对象内存分布布局案例

引入pom文件

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>

代码执行

package org.juc.thread;
import org.openjdk.jol.info.ClassLayout;
/**
 * @ClassName ObjectJOL
 * @Description 对象内存分布布局
 * @Date 2022/8/5 9:33
 **/
public class ObjectJOL {

    public static void main(String[] args) {
        Object o = new Object();
        //转为字节数据可见的字符串打印
        String s = ClassLayout.parseInstance(o).toPrintable();
        System.out.println(s);
    }
}

运行结果
在这里插入图片描述
标记为1的是markword ,一共占位8个字节
标记为2的是class pointer,一共占位4个字节
标记为3的是对齐,前面加起来一共占位12字节,不能被8整除,需要加入四位,一共是16个字节,所以new一个对象占位16字节

案例2

接下里我们new一个对象,在对象中放入数据,在看一下

package org.juc.thread;
import org.openjdk.jol.info.ClassLayout;
/**
 * @ClassName ObjectJOL
 * @Description 对象内存分布布局
 * @Date 2022/8/5 9:33
 **/
public class ObjectJOL {
    public static void main(String[] args) {
        User test = new User();
        test.setName("小明");
        test.setAge(8);
        String s = ClassLayout.parseInstance(test).toPrintable();
        System.out.println(s);
    }
    static class User{
        private String name;
        private int age;
        public User() {
        }
        public void setName(String name) {
            this.name = name;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

运行结果
在这里插入图片描述 1. markword 标记位占8个字节
2. class pointer 指向class地址,占位4个字节
3. instance data 实例数据,name和age存放在这里,分别占位4个字节,一共8个字节
4. padding 对齐,前三点一共占位20字节,不能被8整除,所以需要补位4字节,一共24字节,能够被8整除

对象如何定位?

直接指针:访问速度快
在这里插入图片描述
直接定位就是reference中直接存储的就是堆中对象的地址,如果不止访问对象本身,还需要访问对象类型数据就需要多一次指针定位的开销。
但是直接定位有直接定位的好处,它的速度快,相比于句柄访问(间接定位)节省了一次定位的开销,而且java程序运行过程中,访问对象是一件极其频繁的操作,省去的这一次寻址也是一项非常可观的执行成本。HotSpot虚拟机就是采用这种方式进行对象的访问。

句柄方式,间接指针

在这里插入图片描述
间接指针对象的方式是通过句柄实现的,java堆中划分出一块区域作为句柄池,reference中存储的就是句柄池的地址,句柄池中存储了对象的实例数据与类型数据的地址信息。使用间接定位对象的方式也有优点,堆是垃圾收集器工作的主要区域,在这里会进行频繁的垃圾收集操作,在进行垃圾收集时会涉及大量的对象移动,在频繁的移动对象时,只需要修改句柄的指向实例数据的指针即可,不用频繁的更改栈中的reference变量的值。

对象如何分配?

在这里插入图片描述

  1. 首先对象会尝试在栈中分配,如果栈分配成功,那么在进行垃圾回收的时候,直接就能回收,不需要垃圾回收器。
  2. 如果对象过大的话,直接放入Old老年区,只能通过FGC回收。
  3. 如果对象不大,直接放入Ende区,然后直接GC垃圾回收。在多个线程同时new对象的时候,新对象都会存储在Eden区,这个时候就会产生争夺资源的情况,所以我们需要对线程进行同步优化:我们在Eden中为每一个线程开辟了一个很小的空间,默认是1%,叫做线程私有ThreadLocalAllocationBuffer ,这样就不用同步,不会争夺资源
    然后新生代的Eden区会进行垃圾清除GC,被清除了,就直接删除了,没有清除就进入幸存者 S1区,然后经过多次GC,看AGE到了没有,够age了就进入老年区。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无奈的码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值