• Java对象内存布局和对象头


    Java对象内存布局和对象头

    对象的存储位置

    创建一个object对象,Object o = new Object();,首先我们要明确知道创建对象的那一行代码的存储位置,

    Object相当于一个Object类的模板,类加载的时候放在方法区,存放类的信息

    o:在方法体中,随着方法的调用,存储在栈中栈帧信息中,

    tips:栈帧包括局部变量表,操作数栈,动态链接,返回地址

    new Object():创建的对象信息放在堆空间中

    对象的内存布局

    了解到了对象的存储位置,这时我们要知道对象在堆中存放哪些信息?

    对象在堆内存中存储布局可以划分为三个:对象头,实例数据,填充属性

    1. 对象头:包括Markword和类型指针

       一个对象中都应该包含一下:
      
      • 1
    • hashcode值,自己的hash值,记录在内存中什么地方
    • 给对象可以加锁,标记对象有没有加锁
    • 进行垃圾回收时,要对对象进行标记是否为垃圾对象还有它的垃圾回收次数

    这些基本信息在对象头中markword都记录着,比如GC标记信息,GC次数,同步锁标记,偏向锁持有者,hashcode值

    2.实例数据:可以认为是对象中的一些数据,比如String id;

    3.填充属性:当创建的对象占用内存大小不为8个字节的倍数,会对对象的内存占用补充为8的倍数

    创建对象的内存占用大小

    在64位操作系统当中,对象头中Mark word为8字节,类型指针为8字节,在没有实例数据的情况下,占用内存大小为16个字节

    Mark Word结构

    • hash: 保存对象的哈希码。运行期间调用System.identityHashCode()来计算,延迟计算,并把结果赋值到这里。
    • age: 保存对象的分代年龄。表示对象被GC的次数,当该次数到达阈值的时候,对象就会转移到老年代。
    • biased_lock: 偏向锁标识位。由于无锁和偏向锁的锁标识都是 01,没办法区分,这里引入一位的偏向锁标识位。
    • lock: 锁状态标识位。区分锁状态,比如11时表示对象待GC回收状态, 只有最后2位锁标识(11)有效。
    • JavaThread*: 保存持有偏向锁的线程ID。偏向模式的时候,当某个线程持有对象的时候,对象这里就会被置为该线程的ID。 在后面的操作中,就无需再进行尝试获取锁的动作。这个线程ID并不是JVM分配的线程ID号,和Java Thread中的ID是两个概念。
    • epoch: 保存偏向时间戳。偏向锁在CAS锁操作过程中,偏向性标识,表示对象更偏向哪个锁。

    在这里插入图片描述

    Markword分布图:对象布局,GC回收和后面锁升级就是对象标记MarkWord里面标志位的变换

    25+31+1+4+1+2 = 64位

    在这里插入图片描述

    偏向锁状态时:当线程第一次访问同步代码块并获取锁时,虚拟机将会把对象头中的标志位设为01,同时使用CAS操作把获取到这个锁的线程id记录在对象的Markword中

    轻量级状态:将对象头中的数据都置换为指向栈中锁的记录的指针

    重量级状态:将对象头中的数据都置换为指向重量级锁的指针

    在这里插入图片描述

  • 相关阅读:
    使用Python实现文字的声音播放
    关于VS多个dll相互依赖的问题
    从零开始制作一个割草机器人
    Python Open函数详解
    Vue3理解(6)
    代码随想录二刷 Day 34
    ACM生涯总结
    HHSTU1050型货车转向系及前轴设计(说明书+任务书+CAD图纸)
    SpringCache使用
    AI: 2021 年人工智能前沿科技报告02(更新中……)
  • 原文地址:https://blog.csdn.net/weixin_48304611/article/details/125459803