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

Java基础语言进阶学习——2,对象创建机制与内存布局

对象创建机制与内存布局

学习目标:深入理解对象创建机制与内存布局


文章目录

一、对象创建机制——"对象的诞生之旅"

第1步:类加载检查 - "确认图纸"

第2步:分配内存 - "圈地皮"

第3步:内存空间初始化(零值初始化)- "毛坯房交付"

第4步:设置对象头 - "挂上门牌和档案"

第5步:执行构造方法 - "精装修"

二、对象内存布局 - "对象的身体结构"

1. 对象头

2. 实例数据 - "对象的血肉"

3. 对齐填充 - "为了整齐的补位"

三,实战验证:用JOL工具查看对象内存布局

1. 导入依赖:

2. 查看对象布局:

3.JOL 工具的作用

4.对象内存布局分析

1. Object对象的内存布局

2. Person对象的内存布局

5.运行结果的核心信息

四,总结

1.对象创建机制:

2.对象内存布局:

3.为什么重要:


一、对象创建机制——"对象的诞生之旅"

当我们写下 Person p = new Person("张三", 25); 这行简单的代码时,JVM在幕后为我们上演了一场精彩的"创世"大戏。

详细步骤分解:

第1步:类加载检查 - "确认图纸"

  • 动作:JVM遇到 new 关键字,首先去方法区运行时常量池中查找Person类的符号引用。

  • 检查:这个Person类是否已经被加载、验证、准备、解析和初始化

  • 如果未加载:立即触发类加载过程。这就像盖房子前,要先确认设计图纸是合法且完整的。

  • 示例:如果是第一次创建Person对象,JVM会加载Person.class文件,验证其安全性,为静态变量(如static int count)分配内存并赋零值。

第2步:分配内存 - "圈地皮"

  • 目标:在堆内存中划分一块大小确定的内存空间。对象需要多大,在类加载完成后就已经确定了。

  • 分配方式(由垃圾收集器GC决定):

    a) 指针碰撞

 假设堆内存布局:[已用][已用][BORDER][空闲][空闲][空闲]
 分配一个Person对象(假设24字节)
 分配后:[已用][已用][新Person对象][BORDER][空闲][空闲

  • 适用:堆内存规整(如Serial, ParNew等GC)

  • 原理:用一个指针作为分界点,分配内存就是简单的移动指针

        b) 空闲列表

 假设堆内存布局:[已用][空闲][已用][空闲][空闲][已用]
 虚拟机维护一个列表:空闲块1(地址1, 大小40B), 空闲块2(地址3, 大小80B)...
 从中找一块足够大的空间分配给新对象

  • 适用:堆内存不规整(如CMS GC)

  • 原理:维护一个"空闲地址登记表",从中找到足够大的空间

第3步:内存空间初始化(零值初始化)- "毛坯房交付"

  • 动作:将分配到的内存空间(除了对象头)都设置为零值

  • 目的:保证对象的实例字段不赋初值就能使用,访问到的是数据类型的默认值

// 此时内存中的对象状态:
class Person {private String name;  // = null (零值)private int age;      // = 0 (零值)private boolean isStudent; // = false (零值)// 所有字段都是默认值,就像毛坯房
}

第4步:设置对象头 - "挂上门牌和档案"

对象头就像是对象的"身份证",包含两类信息:

  • Mark Word:存储对象自身的运行时数据

  • 类型指针:指向方法区中的类元数据,表明"这个对象是Person类的实例"

第5步:执行构造方法 <init> - "精装修"

  • 动作:执行构造方法中的代码,按照程序员的意愿初始化对象

public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;   // 把null替换成实际的"张三"this.age = age;     // 把0替换成实际的25}
}

到此,一个真正可用的对象诞生了!

二、对象内存布局 - "对象的身体结构"

对象在堆内存中的存储布局就像人的身体结构,分为三部分:

1. 对象头

这是对象的"大脑和身份证",包含:

a) Mark Word - "状态身份证"

  在64位JVM中,Mark Word是64位(8字节),结构灵活多变:
状态1:普通未锁定状态
   [ 对象哈希码(31位) | 对象分代年龄(4位) | 0 | 01 ]

状态2:偏向锁状态  
   [ 偏向线程ID(54位) | 时间戳(2位) | 1 | 01 ]

状态3:轻量级锁状态
   [ 指向栈中锁记录的指针(62位) | 00 ]

状态4:重量级锁状态
   [ 指向互斥量(重量级锁)的指针(62位) | 10 ]

状态5:GC标记状态
   [ 空,不需要记录信息 | 11 ]

b) 类型指针 - "户口本"

  • 指向方法区中的Person类元数据

  • 让JVM知道"这个对象是Person类型"

  • 在64位JVM中,开启指针压缩后通常是4字节

c) 数组长度(仅数组对象有)

  • 如果是Person[]数组,这里会存储数组长度

2. 实例数据 - "对象的血肉"

这是对象真正存储业务数据的地方,包含所有定义的字段

public class Person {// 实例数据区域开始private int id;           // 4字节private String name;      // 引用类型,开启指针压缩后4字节private int age;          // 4字节  private boolean married;  // 1字节private double salary;    // 8字节// 实例数据区域结束
}

字段排列顺序规则

  1. 父类字段在子类之前

  2. 默认策略:按数据类型的长度从大到小排列

  3. 相同长度字段,引用类型优先

实际内存中可能的排列顺序:

 [对象头(12字节)]
 [double salary]         8字节 - 最长
 [int id]                       4字节  
 [int age]                    4字节
 [String name引用]    4字节 - 引用类型
 [boolean married]    1字节 - 最短
[对齐填充]                 7字节(为了8字节对齐)

3. 对齐填充 - "为了整齐的补位"

  • 目的:HotSpot要求对象大小必须是8字节的整数倍

  • 原因:CPU读取内存时,按块读取(通常是8字节),对齐后能提高访问效率

 计算上面Person对象的大小:
 对象头: 12字节 (Mark Word 8字节 + 类型指针4字节)
 实例数据: 8 + 4 + 4 + 4 + 1 = 21字节  
 总计: 12 + 21 = 33字节
 需要对齐填充: 需要补7字节到40字节(8的倍数)
 最终对象大小: 40字节

三,实战验证:用JOL工具查看对象内存布局

1. 导入依赖

import org.openjdk.jol.info.ClassLayout;

导入 JOL 工具的ClassLayout类,该类是 OpenJDK 提供的用于解析对象内存布局的核心类,可通过parseInstance()方法解析对象,toPrintable()方法输出内存布局详情。

2. 查看对象布局

import org.openjdk.jol.info.ClassLayout;public class ObjectLayoutDemo {public static void main(String[] args) {Object obj = new Object();System.out.println(ClassLayout.parseInstance(obj).toPrintable());Person person = new Person(1, "张三", 25);System.out.println(ClassLayout.parseInstance(person).toPrintable());}
}class Person {private int id;private String name; private int age;private boolean married;public Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}
}

详细分析:

  1. 主类ObjectLayoutDemo主方法main中执行了两个核心操作:

    • 创建Object类实例obj,并打印其内存布局;
    • 创建Person类实例person,并打印其内存布局。
  2. 自定义类Person包含 4 个私有字段和 1 个构造方法:

    • 字段:id(int 类型)、name(String 引用类型)、age(int 类型)、married(boolean 类型);
    • 构造方法:初始化idnameagemarried未显式初始化,默认值为false

3.JOL 工具的作用

JOL(Java Object Layout)是用于分析 Java 对象在 JVM 中内存结构的工具,能直观展示对象的内存组成,包括:

  • 对象头(Object Header):存储对象的元数据(如哈希码、锁状态、类指针等);
  • 实例数据(Instance Data):对象的字段数据(基本类型值或引用地址);
  • 对齐填充(Padding):为满足 JVM 对对象大小的对齐要求(通常是 8 字节的整数倍)而补充的空白字节。

4.对象内存布局分析

JVM 中对象的内存布局受JVM 位数(如 64 位)、指针压缩开关(默认开启)等因素影响。以下基于64 位 JVM + 默认指针压缩UseCompressedClassPointers开启)分析。

1. Object对象的内存布局

Object类没有自定义字段,其内存仅包含对象头和可能的对齐填充

  • 对象头(12 字节)

    • Mark Word(8 字节):存储对象的哈希码、GC 分代年龄、锁状态标记等信息(64 位 JVM 固定 8 字节);
    • Class Pointer(4 字节):指向对象的类元数据(Object.class),因开启指针压缩,从 8 字节压缩为 4 字节。
  • 对齐填充(4 字节):对象总大小需为 8 字节的整数倍(JVM 对齐要求)。对象头 12 字节不是 8 的倍数,需补充 4 字节填充,最终总大小为16 字节

2. Person对象的内存布局

Person有 4 个字段,内存布局包括对象头实例数据对齐填充

  • 对象头(12 字节):与Object对象相同(Mark Word8 字节 + Class Pointer4 字节)。

  • 实例数据(13 字节):存储 4 个字段的数据(按字段定义顺序或 JVM 优化重排,此处按逻辑顺序分析):

    • id(int):4 字节(占偏移量 12-16);
    • name(String 引用):4 字节(存储 String 对象的地址,占偏移量 16-20);
    • age(int):4 字节(占偏移量 20-24);
    • married(boolean):1 字节(占偏移量 24-25)。
  • 对齐填充(7 字节):总大小 = 对象头(12) + 实例数据(13) = 25 字节,需对齐到 8 的整数倍(下一个倍数为 32),因此补充 7 字节填充,最终总大小为32 字节

5.运行结果的核心信息

执行代码后,输出会包含类似以下的关键信息(不同 JVM 版本可能略有差异):

  • Object对象:显示总大小 16 字节,包含 8 字节mark word、4 字节class pointer、4 字节padding

  • Person对象:显示总大小 32 字节,包含 12 字节对象头、13 字节实例数据(4+4+4+1)、7 字节填充,字段偏移量与上述分析一致。

四,总结

1.对象创建机制

  • 类加载 → 分配内存 → 零值初始化 → 设置对象头 → 执行构造方法

  • 分配内存方式:指针碰撞(规整堆)、空闲列表(不规整堆)

2.对象内存布局

  • 对象头:Mark Word(运行时数据)+ 类型指针(类信息)

  • 实例数据:程序定义的字段,按特定策略排列

  • 对齐填充:保证8字节对齐

3.为什么重要

  1. 性能优化:理解内存布局有助于写出缓存友好的代码

  2. 并发编程:synchronized锁信息存储在Mark Word中

  3. 故障诊断:内存溢出时知道对象在内存中的样子

  4. 面试必考:这是考察JVM理解深度的经典问题

记住这个生动的比喻:

对象创建就像造房子:确认图纸(类加载) → 圈地皮(分配内存) → 毛坯房(零值初始化) → 挂门牌(对象头) → 精装修(构造方法)


内存布局就像房子的结构:门牌档案(对象头) → 房间内容(实例数据) → 为了整齐的装饰(对齐填充


http://www.dtcms.com/a/566075.html

相关文章:

  • 网站seo啥意思怎么做罗田县建设局网站
  • 基于yolov8的果蔬识别检测系统python源码+onnx模型+数据集+精美GUI界面
  • 网站建设合同电子版苏州网页制作报价
  • 廊坊网站建设方案策划民治做网站
  • 走路摆臂幅度大给人影响差-----坏习惯
  • TRO重磅消息 野生动物插画师Roger Hall跨境维权风暴来袭
  • ABB焊接机器人节气装置
  • Linux 孤儿进程和僵尸进程详解
  • jsp做网站用什么封装字符串餐饮加盟什么网站建设
  • 做网站挂谷歌广告赚钱吗电子商务网站模板html
  • 基于 OpenVINO 实现 SpeechT5 语音合成模型本地部署加速
  • 北京市建设工程审核在哪个网站打车软件app开发
  • 怎么做站旅游网站上泡到妞主流网站宽度
  • 【底层机制】解析Espresso测试框架的核心原理
  • 网站如何做中英文效果wordpress主题开发培训
  • PostIn零基础学习 - 快速对接口进行调试
  • 网站建设沛宣北京vi设计公司哪
  • 高明网站建设报价品牌网站建设创意新颖
  • HTML DOM outerHTML 属性
  • SpringBoot 登录验证码
  • Spring Al Alibaba
  • 陕西民盛建设有限公司网站pageadmin的最新版本
  • 如何自己做个网站网站xml
  • 易语言怎么制作网站临淄辛店今天招聘信息
  • 相亲网站源码php模版营销网站的概念
  • css文档流
  • C#进阶11:C#局部路径规划算法_DWA
  • 基于Vue人脸识别的智慧课堂学习行为分析系统f36fy939(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • Kotlin线程池newFixedThreadPoolContext与约束协程运行的线程数量limitedParallelism
  • 网站年报公示怎么做站外seo是什么