Java对象在内存中存储结构

使用基于物质点法(MPM)的Anura3D模拟沙柱坍塌 本博客使用开源软件Anura3D软件模拟了一个沙柱坍塌的过程,这个软件是基于基于物质点法(MPM)设计的 阅读详情

Java对象存储:(HOTSPOT虚拟机)

一个Java对象可以分为三部分存储在内存中,分别是:

  • 对象头Object Header
  • 实例数据Instance
  • 对齐填充Padding

在这里插入图片描述

什么是对象头,具体包括什么

在HotSpot虚拟机中,对象头分为两部分(普通对象)

  • 1.对象自身的运行时数据: 包括存储哈希码,GC分代年龄,锁状态标记,线程持有的锁,偏向锁ID,偏向时间戳等.这部分被叫做mark word,在32位和64位的虚拟机分别占32bits和64bits.
  • 2.对象的类型指针: 即指向对象的类元数据的指针.虚拟机可以通过该指针判定对象实例属于那个类.

注:在Java对象中比较特殊的是数组,一个数组实例的对象头中必须包含数组的长度.JVM可以通过对象头中的数组长度数据来判定数组的大小,这是访问数组类型的元数据是无法得知的

JVM中对象头有两种:

1.普通对象
Object Header: 包括mark word和class pointer
2.数组对象
Object Header : 包括mark word,class pointer和array length
数组特有的length ,JVM需要通过数组对象头的length来判定数组的大小.

                                Mark Word

64位虚拟机
在这里插入图片描述
32位虚拟机在这里插入图片描述

Mark Word分析 (64位):

  • 对象的hashcode(identity hash code):
    占31bit,根据内存地址生成的hash值.

  • GC分代年龄:
    age 占4bits,在GC过程中,如果新生代对象在Survivor区复制一次,年龄+1.当对象年龄达到设定的阈值时,对象将会进入老年代.或者有一半的的对象年龄相等,则大于该年龄的对象直接进入老年代.默认情况GC年龄阈值为15.因为age只占4位 ,所以最大值为1111= 15.

  • 锁标志位: 占2bit位,希望用尽可能少的二进制位表示尽可能多的信息,所以设置了锁的标记.该标记的值不同,整个mark word 表示的含义不同.

  • biased_lock(是否为偏向锁) : 对象是否为偏向锁,只占1个bit. 为1时表示对象启用偏向锁,为0表示对象没有偏向锁.

    无锁和偏向锁的锁标志都是01 ,区分的方式是通过1bit的是否为偏向锁(biased_lock).偏向锁的这1bit等于1,无锁这一位则为0

  • 锁的状态

    • new (未锁定状态)
      在一个对象刚new出来的时候,没有线程竞争,就是一个普通对象,不需要加锁,此时biased_lock为1,锁的标志位为01 , 表示无锁可偏向 . ( 如果计算了对象的hashcode ,则会记录对象的hashcode,锁的标志位为01.biased_lock位置为0. 此时表示无锁不可偏向状态)

    • 偏向锁:biased_lock
      如果已经计算了对象的hashcode ,则表示该锁不能偏向 .直接升级为轻量级锁.(对象的hashcode和偏向线程id只能存储一个)
      1.当第一个线程A来获取资源的时候,这个时候只有线程A一个,没有其他线程来竞争,他会将biased_lock标志位置为1,锁标志为01, 表示已经偏向它的状态.线程ID也会记录A的id.
      2.当A线程再次获取该资源的时候,JVM发现mark word里面的线程id是A的id,锁的标志位是01,biased_lock是1,表示A已经获得该偏向锁.

    • 轻量级锁(自旋,自旋锁,look-free,CAS轻量级锁):
      当线程B尝试获取该锁时(此时有了锁的竞争),JVM发现此时锁处于偏向状态,mark word的线程id记录的是A,此时线程B会尝试通过CAS的方式(在用户空间)获取锁.两个线程都将对象的hashcode复制到自己新建的用于存储锁的记录空间LockRecord,通过CAS的操作,将对象的mark word的内容修改为自己新建的记录空间的地址来竞争mark word.成功则获取资源,失败则继续CAS操作.
      自旋的线程在自旋过程中,成功获取资源,整个状态仍然处于轻量级锁的状态.

    • 重量级锁:

      竞争加剧 在jdk6: 自旋锁自旋次数超过10,或者等待线程超过CPU核数的二分之一,升级为重量级锁
      jdk6以后:jdk自适应自旋,来判断什么时候升级

      自旋的线程将被阻塞,需经过os,提供一个等待队列和一个竞争队列.等待操作系统的调度

  • 当前线程指针: 存放获取偏向锁的线程id,占54bit

  • Epoch: 偏向锁的时间戳,占2bit

  • ptr_to_lock_record: 轻量级锁状态下,指向栈中锁记录的指针。

  • ptr_to_heavyweight_monitor: 重量级锁状态下,指向对象监视器Monitor的指针。

Class Pointer (类型指针)

这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例.
-XX:+UseCompressedClassPointers 为4字节(默认开启) 不开启为8字节 (对象属于哪个Class)

array length(数组特有)

如果对象是一个数组,那么对象头还要有额外的空间存储数组的长度,JVM可以通过对象头中的数组长度数据来判定数组的大小,这是访问数组类型的元数据是无法得知的. 长度为4个字节

实例数据(Instance)

对象头是对象的额外开销,只有实例数据才是一个对象实例存储的有效信息,也是在程序代码中所指定的各种类型的字段内容.这部分内容同时记录了子类从父类继承所得的各类型数据.

-XX:+UseCompressedOops 为4字节(默认开启) 不开启为8字节 Oops Ordinary Object Pointers(成员变量的引用 比如Object o)

对其填充(padding)

对齐填充在对象数据中并不是必然的,只是起着占位符的作用,没有特别含义.HotSpot要求对象起始地址必须是8字节的整数倍.对象头的大小刚好符合要求,因此当实例数据没有对齐时,就由对齐填充来对齐数据.

如何获取的元数据

虚拟机在加载类的时候会将类的信息,常量,静态变量和即时编译器编译后的代码等数据存储在方法区(Method Area).类的元数据,即类的数据描述也被存在方法区.我们知道对象头中会存有对象的类型指针,通过类型指针可以获取类的元数据.因此,对象的类型指针其实指向的是方法区的某个存有类的信息地址
有两种对象定位的方法:(间接和直接)

通过句柄访问对象(间接)

对象的类型指针被放在句柄池中;

通过实例数据指针去堆中找对象,同时通过类型数据指针去方法区找对象的类型
在这里插入图片描述

通过Reference指针直接访问对象(直接)

对象的类型指针被存放在对象本身的数据中
先通过实例数据指针去堆中找到对象,再通过类型数据指针去方法区找对象的类型.
在这里插入图片描述

对象的基本存储方式:

  • 对象的引用:存储在栈中
  • 对象的实例数据:存储在堆中
  • 对象的元数据:存储在方法区

补充

在jdk8中为什么大于4秒钟的时候才会有偏向锁状态?
其实这是因为虚拟机在启动的时候对于偏向锁有延迟。
因为在项目启动的时候,有大量的同步块(synchronized),多个线程访问的时候,需要消除偏向锁。会很麻烦,反而会降低效率。
-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 修改上面的jvm参数,可以开启jvm偏向锁延迟配置,延迟为0
-XX:-UseBiasedLocking关闭偏向锁

锁状态转换:

代码示例

public class ObjectTest {
    static ObjectTest a = new ObjectTest();  // 1
    public static void main(String[] args) {
        System.out.println("new 后"+ClassLayout.parseInstance(a).toPrintable());

        a.hashCode();   // 2
        System.out.println("计算hashcode后"+ClassLayout.parseInstance(a).toPrintable());

        synchronized (a) {   // 3
            System.out.println("偏向后"+ClassLayout.parseInstance(a).toPrintable());
        }
        
        new Thread("t1"){   // 4
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                lock();
            }
        }.start();

        new Thread("t2"){  //5
            @Override
            public void run() {
                lock();
            }
        }.start();
    }

    public static void lock(){
        synchronized (a){
            System.out.println(Thread.currentThread().getName()+ClassLayout.parseInstance(a).toPrintable());
        }
    }
}

添加依赖

<dependencies>
        <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.11</version>
        </dependency>
    </dependencies>

通过ClassLayout.parseInstance(Instance).toPrintable()方法查看对象布局.

new一个对象, 一开始为无锁可偏向状态.有线程操作 ,则偏向该线程,设置偏向线程id为该线程id.
在这里插入图片描述
如果new一个对象之后计算了该对象的hashcode,则锁状态为 无锁不可偏向状态 ,会存储hashcode值 , 有线程来会直接升级为轻量级锁.
在这里插入图片描述
new一个对象,先有一个线程, 则偏向线程id设置为该线程id ,又来一个线程,有了锁的竞争 ,则升级为轻量级锁.
在这里插入图片描述

十九、帧间预测编码_2、解码、显示顺序与图像管理、参考帧管理 一、基本概念 1.1H.264的解码顺序和显示顺序: 解码过程中,每一帧的数据按照相应的NAL Unit在码流中的顺序传入解码器进行解码 由于B帧的存在,视频帧在输出时会进行顺序重排 1.2frame_num与POC frame_num:表示解码顺序 POC:表示显示顺序(picture_order_count) 在H.264的码流中,表示解码顺序和显示顺序分别有相应的语法元素表示。这两个值都会在码流中保存,并在读取slice信息时解析(SliceHeader中) 1.3参考帧列表 某一帧图像在解 阅读详情

相关推荐

告别JTAG!用Artix-7和SPI Flash实现FPGA远程升级的保姆级教程

本文详细介绍了如何利用Artix-7 FPGA和SPI Flash实现FPGA远程升级(OTA)的完整方案。通过硬件连接、Vivado工程配置和STM32模拟更新等步骤,帮助开发者告别传统的JTAG烧录方式,实现高效、安全的远程固件更新,特别适用于嵌入式系统开发中的现场维护场景。

weixin_33964987的博客 364

【转载】Java对象在内存的结构

Java对象在内存的结构

weixin_41432808的博客 1084

在工作台 LS-DYNA 中检索和变换反作用力分量

在结构仿真中,通常需要由施加的位移或速度边界条件产生的反作用力。此外,通常需要根据用户定义的坐标系解析反作用力分量。在本文中,详细介绍了在Workbench (WB) LS-DYNA 中,相对于用户定义的坐标系检索和变换反作用力分量的过程。

jkh920184196的博客 885

【jvm】一文带你搞懂java对象在内存中具体的结构(八股必背)

当一个 Java 对象被创建时,它会被。java对象在内存中的结构可以分为三个重要的部分——对象头(Header)、实例数据(Instance Data)、对其填充(Padding)对象头主要是由两部分或三部分组成,、类指针数组(三部分):MarkWord、类指针、数组长度。

miles067的博客 1604

QDMA工程搭建/windows驱动编译与性能测试

请注意,根据您的目标操作系统,您可能需要在windows启动配置中启用测试签名的驱动程序,以便启用此驱动程序的安装。右键单击设备,选择更新驱动程序软件,然后选择构建的QDMA驱动程序的文件夹(通常为。创建一个新工程,在IP Catalog中搜索QDMA,双击创建qdma ip核。驱动程序安装安装驱动程序最简单的方法是通过Windows的“设备管理器”。如果系统提示未经验证的驱动程序发布者,请选择无论如何安装此驱动程序软件。本节主要介绍QDMA驱动在Windows系统的源文件、编译和安装过程。

qq_28455081的博客 2287

UE5深度图与Mask图渲染实战:从基础到高级应用

本文详细解析了在UE5中渲染深度图与Mask图的完整实战流程。从启用电影渲染队列、配置自定义深度模板通道等前期准备,到构建即用型深度图材质网络与精准物体Mask生成,并深入探讨了二者结合在NPR风格化、程序化雾气及AI工作流(如ComfyUI)中的高级应用,为影视、游戏后期与AI创作提供了高效的解决方案。

weixin_29001419的博客 350

java对象的内存布局

对象的内存布局分为两种,普通对象和数组对象。

童小绿 学无止境 1346

寄存器与计数器设计(Verilog)

always @(posedge Reset or posedge Clock)//请在括号中补充敏感信号列表。always @(negedge Resetn , posedge Clock)//请在括号中补充敏感信号列表。always @(negedge Resetn,posedge Clock)//请在括号中补充敏感信号列表。//为了便于自动评测,请勿更改n的值。//为了便于自动评测,请勿更改n的值。//为了便于自动评测,请勿更改n的值。//为了便于自动评测,请勿更改n的值。

M_inherit的博客 364

Java对象的内存结构

Java 对象的内存结构对于理解 Java 内存管理和性能优化至关重要。本文将详细介绍 Java 对象的内部结构,并提供查看这些信息的方法。对象头 (Header)实例数据 (Instance Data)填充数据 (Padding Data)

斌斌(Java) 1757

基于C#通过PLCSIM ADV仿真软件实现与西门子1500PLC的S7通信方法演示

基于C#通过PLCSIM ADV仿真软件实现与西门子1500PLC的S7通信方法演示

Robot_PLC_HMI_Automation 3162

信息传输仿真:卫星通信系统仿真_(12).基于SystemVue的卫星通信仿真

SystemVue是Cadence公司开发的一款用于系统级设计和仿真的软件工具。它主要用于无线通信系统的设计和验证,特别是在卫星通信、雷达、射频和微波通信等领域。SystemVue提供了一个集成的环境,用户可以通过拖拽和连接各种预定义的模块来构建复杂的通信系统模型,从而进行性能分析和优化。

2401_87715305的博客 1370

java对象在内存中的结构(HotSpot虚拟机)

一、对象的内存布局 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。 从上面的这张图里面可以看出,对象在内存中的结构主要包含以下几个部分: Mark Word(标记字段):对象的Mark Word部分占4个字节,其内容是一系列的标记位,比如轻量级锁的标记位,偏向锁标记位等等。 Klass Pointer(Class对象指针):Class对象指针的大小也是4个字节,其指向的位置是对象对应的Class

yygr的博客 1278

100天精通Python(可视化篇)——第98天:Pyecharts绘制多种炫酷日历图参数说明+代码实战

一、日历图介绍 二、基础配置 1. 配置项类 2. 添加函数 3. 日期标签配置 4. 坐标系配置 三、日历图实战 1. 基础日历图 2. 日历热图

努力让自己发光,对的人才能迎着光而来 2万+

java对象内存存储结构理解

一、java程序的操作系统的内存申请 操作系统的空间申请是以进程为单位。进程包含至少一个线程,当我们运行一个java程序时,开启一个javaw虚拟机进程,并且默认构建一个线程(即main线程),进程向操作系统申请操作系统空间。操作系统空间有两种使用方式,一种叫做栈,另一种叫做堆。java程序中,一个线程就是一个栈,一个进程只有一个堆。如果我们在java程序中没有额外的构建线程,那我们称这个ja...

Slayer456的博客 3923

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

java对象底层原存储结构图解_Java对象在内存中的存储结构图解

Java对象在内存中的存储结构图解Java对象在内存中的存储结构图解public class TestStudent {public static void main(String[] args) {int n = 10; //栈存储int m = 10; //栈存储Student stu = new Student();//属性赋值stu.name="张三";System.out.print...

weixin_29196891的博客 358

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java对象在内存中存储结构和synchronized原理

Java对象在内存中存储结构和synchronized原理对象在内存中存储的结构对象头实例数据对齐填充synchronized的锁的原理锁升级wait和notify的原理:wait和notify为什么需要在synchronized里面?Hotspot JVM中,32位机器下,Integer对象的大小是int的几倍? 对象在内存中存储的结构 对象在内存中存储的结构由三部分组成:对象头、实例数据、对齐填充。 对象头 根据类型可分为两种 普通对象包含:Mark Word、元数据指针(Klass Pointer

weixin_39596725的博客 489

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java对象在内存中的存储结构图解

public class TestStudent { public static void main(String[] args) { int n = 10; //栈存储 int m = 10; //栈存储 Student stu = new Student(); //属性赋值 stu.name="张三"; System.out.println(stu.name);...

Song_MJ的博客 5417

java对象在内存中结构_Java Objects Memory Structure/Java对象在内存中的存储结构 [转]...

One thing about Java that has alwaysbothered me, given my C/C++ roots, is the lack of a way to figureout how much memory is used by an object. C++ features the sizeofoperator, that lets you query the ...

weixin_35831969的博客 259

java对象底层原存储结构图解_理解Java对象:要从内存布局及底层机制说起,话说…....

前言大家好,又见面了,今天是JVM专题的第二篇文章,在上一篇文章中我们说了Java的类和对象在JVM中的存储方式,并使用HSDB进行佐证,没有看过上一篇文章的小伙伴可以点这里:《类和对象在JVM中是如何存储的,竟然有一半人回答不上来!》这篇文章主要会对Java对象进行详细分析,基于上一篇文章,对Java对象的布局及其底层的一些机制进行解读,相信这些会对后期JVM调优有很大的帮助。对象的内存布局在上...

weixin_34333092的博客 484

一篇了解Java 对象底层存储结构

摘要: Java对象在JVM堆内存中由三部分组成:对象头(包含运行时标记Mark Word和类型指针Klass Pointer)、实例数据(存储字段值,JVM会优化排列顺序以减少内存浪费)以及对齐填充(确保对象大小为8字节倍数)。对象头存储元信息如锁状态、哈希码等,类型指针指向类元数据。64位JVM默认启用压缩指针优化,将引用从8字节压缩至4字节。数组对象额外包含长度字段。字段排列遵循父类优先、大字段靠前等规则,通过重排和填充优化内存访问效率。最终对象大小总为8字节对齐,以适配CPU内存访问特性。

qq_73332829的博客 473

JVM内存结构、Java内存模型以及Java对象模型之间的区别

JVM内存结构、Java内存模型以及Java对象模型之间的区别 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和Java对象模型,这就是三个截然不同的概念,但是很多人容易弄混。 可以这样说,很多高级开发甚至都搞不不清楚JVM内存结构、Java内存模型和Java...

Rika_Sir_Zhong的博客 543

java创建变量的过程_Java 对象创建过程

对象创建在语言层面,创建一个对象通常仅一个new关键字就可以解决了,但是在虚拟机中,对象的创建要经过一个复杂的过程。方法区中的常量池当虚拟机遇到一个new关键字时,首先去方法区中的常量池中找有没有这个类的符号引用,并检查这个符号代表的类是否已经被加载、解析和初始化过,如果没有先执行类的加载过程。堆内存类加载完成后,接下来在虚拟机中的堆上划分出一块内存,存储类的对象(大小在类加载完成后,根据其内部的...

weixin_42480812的博客 383

JVM内存结构 VS Java内存模型 VS Java对象模型

Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模型和Java对象模型,这就是三个截然不同的概念,但是很多人容易弄混。可以这样说,很多高级开发甚至都搞不不清楚JVM内存结构、Java内存模型和Java对象模型这三者的概念及其间的区别。甚至我见过有些面试官自己也搞的不是太清楚。不信的话,你去网上搜索Java内存模型,还会有很多文章的内容其实介绍的是JVM内存结构。

rita_0567的博客 784

Java对象在内存的结构

一、内存布局 对象在内存中存储的结构由三部分组成:对象头、实例数据、对齐填充。 对象头 MarkWord(标记字段) :哈希码、分代年龄、锁标志位、偏向线程ID、偏向时间戳等信息。Mark Word被设计成了一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。例外:如果是数组的话,还需要有一块区域存放数组大小,因为没办法从元数据确认数组大小,所以要存...

Java_No2的博客 360

Java对象内存结构详解

JVM要求对象起始地址必须是8字节的整数倍,因此可能需要填充字节(0-7字节)对象头包含运行时元数据和控制信息,占12字节(压缩指针)或16字节(未压缩)指向方法区中的类元数据的指针(开启压缩指针时为4字节,否则8字节):避免包装类(Integer等)的内存开销。:对于不变对象可复用(如String池)如果是数组对象,额外存储数组长度。:手动排列字段可减少填充。下方公众号资料免费获取。

未来会更好的博客 1035

【Java基础】内存图、类和对象的关系

在学习java内存图之前,我们需要先去了解一下java是如何运行的。首先我们在电脑桌面上新建一个Hello.java的文件。在里面我们去写一些简单的输出代码。想要运行这个文件,我们打开终端,输入javac命令,桌面上会生成一个Hello.class文件。之后继续输入java Hello命令,就能输出Hello World了。以上是运行java文件的一个简单流程,我们通过javac命令将.java文件编译成.class文件,那么这两个文件有什么区别呢?

2501_91676654的博客 881
上一篇: 设计模式-单例模式
下一篇: JVM-内存分配策略和垃圾回收策略
Java-fly
博客等级 码龄9年 13粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值