Java对象内存布局

文章目录

  • 1、对象头
    • 对象标记Mark Word
    • 类元信息(又叫类对象指针)Class Pointer
    • 数组长度(Array Length)(可选)
  • 2、实例数据(对象体)
  • 3、对齐填充
  • 4、指针压缩
  • 5、再聊对象头的MarkWord
  • 6、JOL分析对象在Java虚拟机中的大小和布局

Object object = new Object() 谈谈你对这句话的理解?一般而言JDK8按照默认情况下,new一个对象占多少内存空间

在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:

  • 对象头

  • 实例数据

  • 对齐填充

对象头分为对象标记(markOop)类元信息 (klassOop)

类元信息存储的是指向该对象 类元数据(klass)的首地址。

引出问题

public class Demo01 {
    public static void main(String[] args) {
        Object o = new Object();//?new 一个对象,内存占多少,记录在哪里?

        System.out.println(o.hashCode());//356573597,这个hashCode又是记录在哪里的

        synchronized (o){//加锁信息又是记录在哪里的

        }
        System.gc();//手动垃圾收集中,15次可以从新生代到养老区,那这个次数又是记录在哪里的
    }
}

刚刚几个问题都保存在对象标记

贴一张对象内部结构图:
在这里插入图片描述

1、对象头

对象标记Mark Word

用于存储自身运行时的数据例如CG标志位、哈希码、锁状态等信息

在这里插入图片描述

在64位系统中,MarkWord占了8个字节,类型指针占了8个字节,一共是16个字节

类元信息(又叫类对象指针)Class Pointer

所谓的类元信息(类对象指针)其实就可以说是模板,用于存放方法区Class对象的地址,虚拟机通过这个指针来确定这个对象是哪个类的实例

在这里插入图片描述

对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例

数组长度(Array Length)(可选)

如果对象是一个Java数组,那么该字段必须存在,用于存放数组长度,占用32位字节

2、实例数据(对象体)

实例数据:存放类的属性(Field)信息,包括父类的属性信息,这部分内存按4字节对齐

3、对齐填充

用来保证Java对象所占内存字节数为8字节的倍数,

对齐填充:虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐这部分内存按8字节补充对齐。对象头本身是8的倍数,当对象的实例数据不是8 的倍数时,需要使用填充数据来保证8 字节的对齐

来个案例,对象头16+实例数据5+对齐填充3=24字节

在这里插入图片描述

4、指针压缩

对于对象指针来说,如果JVM中的对象数量过多,使用64位的指针将浪费大量内存(比32位多浪费50%),为了节约内存可以使用选项+UseCompressedOops 开启指针压缩

以下类型指针会从64位压缩到32位:

  • Class对象的属性指针(静态变量)
  • Object对象的属性值指针(成员变量)
  • 普通对象数组的元素指针

5、再聊对象头的MarkWord

在这里插入图片描述

底层源码涉及到的一些字段:

  • hash:保存对象的哈希码
  • age: 保存对象的分代年龄
  • biased_lock: 偏向锁标识位
  • lock: 锁状态标识位
  • JavaThread :保存持有偏向锁的线程ID
  • epoch: 保存偏向时间戳

6、JOL分析对象在Java虚拟机中的大小和布局

导入依赖

Demo测试:

public class JolDemo {
    public static void main(String[] args) {
        //Vm的细节详细情况
        System.out.println(VM.current().details());
        //所有的对象分配的字节都是8的整数倍
        System.out.println(VM.current().objectAlignment());
    }
    /**
     * 运行情况:
     * # Running 64-bit HotSpot VM.
     * # Using compressed oop with 3-bit shift.
     * # Using compressed klass with 3-bit shift.
     * # Objects are 8 bytes aligned.
     * # Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
     * # Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
     *
     * 8
     *
     * 进程已结束,退出代码0
     */
}

看看Object 类:

Object obj = new Object()

public class JolDemo {
    public static void main(String[] args) {
        Object o = new Object();//----------新建一个Object对象就是  16bytes
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}

在这里插入图片描述

在这里插入图片描述

为什么类型指针是4字节?之前不都是说是8字节的吗?(因为压缩指针默认开启了)

再来看看自定义的类:

public class JolDemo {
    public static void main(String[] args) {
        Customer c1 = new Customer();
        System.out.println(ClassLayout.parseInstance(c1).toPrintable());
    }

}
//只有对象头,没有实例数据,依然是16byte
class Customer{

}
/**
 * 运行结果:
 * com.hh.demo.Customer object internals:
 *  OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
 *       0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
 *       4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
 *       8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
 *      12     4        (loss due to the next object alignment)
 * Instance size: 16 bytes    
 * Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
 *
 *
 * 进程已结束,退出代码0
 */
public class JolDemo {
    public static void main(String[] args) {
        Customer c1 = new Customer();
        System.out.println(ClassLayout.parseInstance(c1).toPrintable());
    }

}
//有了对象头,且有实例数据(int+boolean),它进行了对齐填充,到了24byte
class Customer{
    int id;
    boolean flag = false;
}
/**
 * 运行结果:
 * com.hh.demo.Customer object internals:
 *  OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
 *       0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
 *       4     4           (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
 *       8     4           (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
 *      12     4       int Customer.id                               0
 *      16     1   boolean Customer.flag                             false
 *      17     7           (loss due to the next object alignment)
 * Instance size: 24 bytes
 * Space losses: 0 bytes internal + 7 bytes external = 7 bytes total
 *
 *
 * 进程已结束,退出代码0
 */

GC年龄采用4位bit存储,最大位15,例如MaxTenuringThreshold参数默认值就是15

  • 对象分代年龄最大就是15

在这里插入图片描述

  • 我们假如想直接把分代最大年龄修改为16会直接报错。
-XX:MaxTenurningThreshold=16

在这里插入图片描述

尾巴参数说明(压缩指针相关)
压缩指针相关的命令(压缩指针是否开启对我们new一个对象是不是16字节的影响)

查看当前JVM运行参数的指令

  • java -XX:+PrintCommandLineFlags -version

压缩指针默认是开启的
(这也就解释了为什么前面的类型指针是4个字节,节约了内存空间)
在这里插入图片描述

假如不压缩的情况?我们手动关闭压缩指针看看?

+是开启,-就是关闭,所以指令是

  • -XX:-UseCompressedClassPointers
    在这里插入图片描述
    在这里插入图片描述

不管是否开启压缩指针,创建一个对象就是16字节的。(开启压缩指针后缺失的会由对齐填充补充)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/6571.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android ART虚拟机 Space类体系

前言 在ART虚拟机实现中,内存分配和释放的算法是封装在不同的Space中来完成的。而外部使用者只能借助Space及派生类的接口来完成内存的分配与释放。通过阅读这些Space的实现,可以看出ART虚拟机的一个重要的特点就是大量使用映射内存,相较于D…

思维导图软件哪个好?安利八款好用的思维导图软件

当你需要表达和整理复杂的想法、计划和项目时,思维导图软件可以是非常有用的工具。不同的思维导图软件有不同的功能和特点,选择适合自己的软件可以让你更高效地工作和学习。但是你了解思维导图软件哪个好呢?下面就给大家安利八款简单好用的思…

分享99个ASP影音娱乐源码,总有一款适合您

分享99个ASP影音娱乐源码,总有一款适合您 99个ASP影音娱乐源码下载链接:https://pan.baidu.com/s/1pYpAqFUX0xD8KR8GDRyiug?pwd3lja 提取码:3lja Python采集代码下载链接:采集代码.zip - 蓝奏云 我的博客地址:亚…

1Panel开源面板项目GitHub Star数量突破2,000!

截至2023年4月4日18:00,FIT2CLOUD飞致云旗下开源项目——1Panel开源Linux服务器运维管理面板GitHub Star数超过2,000个!

IDE装上ChatGPT,一天开发一个系统

昨天白天在写代码,晚上看了一场直播,是两个技术的直播: 一个是技术总监,一个是号称Java之父的余**。 结果Java之父被技术总监吊打。然后匆匆下播。 技术这玩意,真的就是真的! 白天我开发了一个系统&…

LeetCode.每日一题 2427. 公因子的数目

Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接 我会一直往里填充内容哒! &…

ModuleNotFoundError: No module named ‘gdal‘

目录 一、问题描述 二、解决方法 一、问题描述 在win系统下使用gdal包的时候,使用下面代码pip安装: conda install glob -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ 安装过程中没有报错,但是 import 的时候还是报错了…

Vicuna:与ChatGPT 性能最相匹配的开源模型

Vicuna (由stable diffusion 2.1生成)前言最近由UC Berkeley、CMU、Stanford, 和 UC San Diego的研究人员创建的 Vicuna-13B,通过在 ShareGPT 收集的用户共享对话数据中微调 LLaMA获得。其中使用 GPT-4 进行评估,发现Vicuna-13B 的性能达到了ChatGPT 和 …

脑外伤最怕后遗症?做好这6大家庭护理措施,防止后遗症

脑外伤是生活中常见的一种情况,主要也就是由于意外或者是其他原因造成的脑部外伤。脑外伤也属于神经系统疾病的一种,最主要是因为对脑部的组织细胞以及神经造成了巨大伤害,从而引起的一系列不良症状的疾病,这种时候也就需要做护理…

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台

憨批的语义分割重制版11——Keras 搭建自己的HRNetV2语义分割平台学习前言什么是HRNetV2模型代码下载HRNetV2实现思路一、预测部分1、主干网络介绍a、Section-1b、Section-2c、Section-3d、Section-42、特征整合部分3、利用特征获得预测结果二、训练部分1、训练文件详解2、LOSS…

python123

文章目录温度转换异常处理百分制成绩转换五分制F正整数AB奇偶求和判断数据类型温度转换异常处理 描述‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪…

数组切分 蓝桥杯 DFS DP

⭐ 数组切分 输入 4 1 3 2 4输出 5⭐ 区间最大值 - 区间最小值 区间长度:说明该区间为连续的自然数 🤠 暴馊dfs (过 50 % 的案例) import java.util.*;public class Main {static int mod 1000000007, n;static int res 0…

OBCP第七章 OB迁移-备份恢复技术架构及操作方法

为什么需要备份恢复 为满足监管要求 防止管理员误操作后,错误数据同步到所有副本,导致数据无法恢复 防止数据库因各种故障而造成数据丢失,降低灾难性数据丢失的风险,从而达到灾难恢复的目的 硬盘驱动器损坏 黑客攻击、病毒 …

九龙证券|券商积极布局A股 新进171家公司前十大流通股东

随着上市公司2022年年报连续出炉,券商自营盘的操作途径同步浮现。Choice数据显示,到4月4日,券商新进171家上市公司前十大流通股东之列,有48家上市公司获加仓。从装备方向来看,制造业、非银金融、电子、电力设备等板块依…

【电源专题】充电过程中指示灯怎么就红绿闪烁或是同时亮

本案例是在工作中发现的,同事测试的时候发现产品充电时指示灯红绿闪烁。正常的表现应该是充电为红灯,充满为绿灯。怎么会出现红绿闪烁的情况呢? 首先前提条件是产品已经量产,并且出货数量巨大,因此是否为个例性问题?通过排查后发现,最终现象是跟着充电器走,使用正常产品…

chatGPT的未来应用有哪些-ChatGPT对未来工作的影响

ChatGPT对未来的影响 ChatGPT 是一种先进的自然语言处理技术,能够处理和理解大量的自然语言数据和信息,具有广泛的应用价值。以下是 ChatGPT 可能对未来的影响: 改变人与计算机的交互方式。ChatGPT 的普及应用,将使得人们可以通过…

聊聊移动端动态化的由来和各流派的优缺点

移动端动态化的由来 “动态化”并不是最近几年才产生的名词,而是从从互联网诞生的初期,这个词就已经出现了。大家所认知的早期互联网,其实就是各种各类的“动态网站”,内容数据和页面外观都不是固定的,都是随着服务器…

命名空间和程序集

目录 一、什么是命名空间 1. 命名空间的作用 2. 命名空间跨文件伸展 3.嵌套命名空间 二、using指令 1. using命名空间指令 2. using别名指令 三、程序集的结构 1. 程序集标识符 2.强命名程序集 一、什么是命名空间 1. 命名空间的作用 命名空间是共享命名空间名的一组…

kotlin协程原理分析

使用kotlin的协程一段时间后,我们或多或少会产生一些疑问:协程和线程有什么关系?协程之间到底怎么来回传递的?协程真的比线程(池)好吗? 初窥 首先我们从最简单协程开始: fun main…

XXX客户挖矿应急响应

此次为真实客户案例! 0x01 前言: 同事反馈,有客户设备告警连接挖矿域名。 0x02 事件分析: 登录设备TOP: CPU巨高!!查。 定位进程: 通过netstat -anop 查看可疑进程: 通过netstat -anop | grep 28564 查看对应进程: