当前位置: 首页 > news >正文

Java 基础(4)—Java 对象布局及偏向锁、轻量锁、重量锁介绍

一、Java 对象内存布局

1、对象内存布局

一个对象在 Java 底层布局(右半部分是数组连续的地址空间),如下图示:
在这里插入图片描述

总共有三部分总成:

1. 对象头:储对象的元数据,如哈希码、GC 分代年龄、锁状态标志、线程持有的锁等等。
2. 实例数据:存储对象实际的数据内容,即程序员定义的各种类型的变量。
3. 对其填充:为了 JVM 能够更快地访问对象内部的数据,会在实例数据后面填充额外的空间,使得对象的大小能够被虚拟机的内存管理系统所整除(一般都是8的倍数)。

具体对象头的大小和实例数据的大小,与 Java 虚拟机的具体实现、对象的类型、虚拟机运行时参数等都有关系,一般不是固定的数值。需要注意的是,数组对象与普通对象的内存布局是不一样的,数组对象会额外存储数组长度信息。

1.1、对象头

点击进入 openjdk 官网

1.1.1、mark word 标记字

对象头两部分组成:

在这里插入图片描述
在这里插入图片描述

1. 对象标记(mark word):储对象的元数据,如哈希码、GC 分代年龄、锁状态标志、线程持有的锁
2. 类元信息(klass pointer):存储的是指向该对象类元数据(klass)所在的首地址。

在 64位操作系统上,Markword 占了8个字节,类型指针占了8个字节,一共占16个字节。也就是说你随便 new 一个对象对象头就直接占了 16个字节(但是不一定,可能会压缩类型指针)。

在这里插入图片描述

1.1.2、klass pointer 类型指针

可以参考下图,类型指针指向方法区,比如有个 Customer 类,new 一个 Customer 实例,这个实例的类型指针指向方法区中的 Customer 类元信息。

在这里插入图片描述

1.2、实例数据

存放类的 Field 数据信息,包括父类的属性信息;如果是数组实例部分,还需要包括数组的长度,这部分内存按照4个字节对齐。

举个例子如下:

public class MarkwordDemo {

    public static void main(String[] args) {
        new Apple();
    }
}
class Apple {
}

直接 new 一个空属性 Apple 实例,在内存中就已经占用16字节(不考虑类型指针压缩),如果 Apple 类中还有其他属性呢?如下所示:

public class MarkwordDemo {

    public static void main(String[] args) {
        new Apple();
    }
}
class Apple {
    int size = 100;
    char a = 'a';
}

一个 int 类型占 4个字节,一个 char 字符占1个字节,所以 new 一个 Apple 实例就会占用 16+5 = 21 个字节,但是最终会占用24个字节,因为 Java 底层为了方便内存管理,需要将其对齐填充,并且一般是8的倍数,所以是24字节。

1.3、对其填充

虚拟机要求对象起始地址必须是8字节的整数倍,填充数据不是必须存在的,仅仅是为了字节对齐,这部分内存按照8字节补充对齐。

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 什么是 Cookie?简单介绍与使用方法

  • 什么是 Session?如何应用?

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • 如何理解应用 Java 多线程与并发编程?

  • 把握Java泛型的艺术:协变、逆变与不可变性一网打尽

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 如何理解线程安全这个概念?

  • 理解 Java 桥接方法

  • Spring 整合嵌入式 Tomcat 容器

  • Tomcat 如何加载 SpringMVC 组件

  • “在什么情况下类需要实现 Serializable,什么情况下又不需要(一)?”

  • “避免序列化灾难:掌握实现 Serializable 的真相!(二)”

  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)

  • 解密 Redis:如何通过 IO 多路复用征服高并发挑战!

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • “打破重复代码的魔咒:使用 Function 接口在 Java 8 中实现优雅重构!”

  • Java 中消除 If-else 技巧总结

  • 线程池的核心参数配置(仅供参考)

  • 【人工智能】聊聊Transformer,深度学习的一股清流(13)

  • Java 枚举的几个常用技巧,你可以试着用用

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)

  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系

  • HTTP、HTTPS、Cookie 和 Session 之间的关系

  • 使用 Spring 框架构建 MVC 应用程序:初学者教程

  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误

  • Java Spring 中常用的 @PostConstruct 注解使用总结

  • 线程 vs 虚拟线程:深入理解及区别

  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别

  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!

  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)

  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)

相关文章:

  • 从算法到应用:DeepSeek 如何重塑 AI 交互新范式?
  • Transformers 是工具箱,BERT 是工具。
  • 响应“十四五”新型储能规划!储能电站如何用高精度电表满足“双向计量”要求?
  • 服务器安装Jupyter Notebook
  • 软考系统架构设计师之物联网与边缘计算笔记
  • 深入解析多表联查(MySQL)
  • ubuntu 20.04 安装源码编译 ros humble过程
  • 基于混合编码器和边缘引导的拉普拉斯金字塔网络用于遥感变化检测
  • c# 数据结构 链表篇 有关单链表的一切
  • java 项目
  • AI多模态论文解读:OmniCaptioner:多领域视觉描述生成框架(附脑图)
  • C语言超详细指针知识(一)
  • 第八天 开始Unity Shader的学习之Blinn-Phong光照模型
  • 聊聊Spring AI的Tool Calling
  • 利用多GPU计算探索量子无序及AI拓展
  • 城市应急安防系统EasyCVR视频融合平台:如何实现多源视频资源高效汇聚与应急指挥协同
  • 力扣第206场周赛
  • 基于Streamlit的智能创业计划生成器开发实践
  • 面试经验分享 | 成都渗透测试工程师二面面经分享
  • 道可云人工智能每日资讯|广东省交通行业算力中心在韶关市揭牌
  • 安阳做网站哪家好/株洲seo
  • 付费 视频 网站 怎么做/企业自助建站
  • 介绍自己的家乡遵义网站建设/微信推广方法
  • 响应式网站建设信息/seo工具有哪些
  • sketch可以做网站交互么/seo品牌优化
  • 易居做网站/今天上海最新新闻事件