Java对象在内存中存储结构

高效敏感词检测API平台对比与选型指南 本文为开发者提供了高效敏感词检测API平台的选型指南。文章对比了专业API平台、头部云厂商、新兴AI服务商及开源方案,从检测能力、集成易用性、成本、稳定性及扩展性五大维度进行分析,并给出实战选型建议,帮助团队根据业务场景快速选择最合适的敏感词检测服务。 阅读详情

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 ,又来一个线程,有了锁的竞争 ,则升级为轻量级锁.
在这里插入图片描述

在anaconda环境中使用conda命令安装cuda、cudnn、tensorflow(-gpu)、pytorch 文章目录在anaconda环境中使用conda命令安装cuda、cudnn、tensorflow(-gpu)、pytorch结论参考资料解释相关命令版本关系版本选择总结:实验 在anaconda环境中使用conda命令安装cuda、cudnn、tensorflow(-gpu)、pytorch 结论 使用conda虚拟环境 使用conda命令安装 最重要的是版本关系(python、cuda、cudnn、pytor或者tensorflow框架)的对应。 参考资料 tensorflow2.x安装 理清GPU、 阅读详情

相关推荐

基于Apache MINA SSHD配置及应用

Apache MINA SSHD是一个基于Java的开源SSH服务器/客户端实现,支持SSH2协议,提供文件传输、shell访问等功能。该代码实现了一个SftpClientService服务类,封装了SFTP文件操作,包括读取文件(readOnce/readLines)和写入文件(writeOnce)等核心功能。通过SftpProperties配置类管理连接参数,并采用Builder模式创建SSH会话。主要特点包括:支持大文件分块传输、自动创建目录、严格的异常处理和...

流沙QuickSand 945

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

Java对象在内存的结构

weixin_41432808的博客 1084

ESP32+ST7789 LCD屏实战:5分钟搞定中文显示与图片渲染(附完整代码)

本文提供了一份详细的ESP32驱动ST7789 LCD屏幕的实战指南。通过清晰的SPI硬件连接说明、ESP-IDF框架下的初始化代码,以及图片渲染与中文字库构建的核心算法,帮助开发者快速实现中文显示与图片渲染功能,并附有完整的代码示例和性能优化技巧。

weixin_29189377的博客 440

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

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

miles067的博客 1604

pi-star图形界面安装指南

pi-star图形界面安装指南,MMDVM热点安装,树莓派3B+热点

blueisman的专栏 1911

毫米波雷达入门知识

毫米波雷达入门知识

ssbzxcvbnm1234567的博客 5447

java对象的内存布局

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

童小绿 学无止境 1346

C++ PCL点云处理实战专栏

工业级点云处理技术学习资源,涵盖电力、建筑、隧道等领域的实战案例。内容分为三阶段:代码原理(算法认知)、动态库(项目验证)和完整代码(定制开发)。

weixin_45196569的博客 1120

Java对象的内存结构

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

斌斌(Java) 1757

YOLOv13涨点改进| CVPR 2026 |独家创新首发、主干改进篇 |利用RIS-PiDiNet主干让YOLOv13更加强大!适合遥感目标检测、小目标检测、旋转目标检测,变化检测,图像分割涨点

🔥本文提出了一种改进的RIS-PiDiNet主干网络,通过引入几何先验构建几何一致性检测器,显著提升了模型在任意方向、结构规则目标场景下的检测性能。包含两个核心模块:S-PDC利用极谐变换的谐波核建模目标结构对称性,RIS-PDC通过SO(2)群平均实现旋转不变性。网络采用基于RIS-block的主干结构并融合轻量级LBP特征,增强了细粒度结构表达能力。实验表明,该方法特别适用于遥感和复杂几何分布场景,能有效提升目标检测的鲁棒性和精度。文章还详细介绍了如何将RIS-PiDiNet集成到YOLOv13框架

Ai缝合怪、助力小伙伴高效发论文 90

Qt EGLFS 图形后端详解

EGLFS (EGL Full Screen) 是Qt框架在嵌入式Linux系统中的高性能图形显示后端,它提供了直接基于EGL和OpenGL ES的硬件加速渲染解决方案。

浩瀚之水的专栏 513

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

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

yygr的博客 1278

RK3399外设驱动之MIPI

RK3399外设驱动之MIPI 文章目录RK3399外设驱动之MIPIMIPI命令解析入口代码mipi显示配置实例rk3399mipi驱动rk mipi驱动注册过程rk32_mipi_dsi.c解析 内核版本 Linux4.4 平台 rk3399 作者 nineyole MIPI命令解析入口代码 MIPI的入口代码如下:kernel\drivers\video\rockchip\screen\lcd_mipi.c static int __init rk_mipi_screen_in

学无止境 2229

java对象内存存储结构理解

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

Slayer456的博客 3923

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

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

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

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

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

weixin_39596725的博客 489

怀旧版电脑GBC模拟器

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

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、付费专栏及课程。

余额充值