JVM之对象的内存布局

简介: JVM之对象的内存布局

JVM之对象内存布局

先来看一道大厂的面试题

一、对象的创建过程

二、对象在内存中的存储布局

2.1、对象头

对象头用于存储对象的元数据信息

对象头又可以分为两块内容:第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别位32bit和64bit,官方称它为 Mark Word。对象头的另一部分是类型指针,指向它的类元数据的指针,用于判断对象属于哪个类的实例,另外,如果对像是一个数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中却无法确定数组的大小。

2.2、实例数据

实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录下来。父类定义的变量会出现在子类定义的变量的前面。各字段的分配策略为longs/doubles、ints、shorts/chars、bytes/boolean、oops(ordinary object pointers),相同宽度的字段总是被分配到一起,便于之后取数据。

2.3、对齐填充

对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。为什么需要有对齐填充呢?由于hotspot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话,就是对象的大小必须是8字节的整数倍。而对象头正好是8字节的倍数。因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

最后再给个图帮助理解记忆

三、使用JavaAgent测试Object的大小

3.1 对象大小(64位机)

3.2 观察虚拟机配置

java -XX:+PrintCommandLineFlags -version

3.3 普通对象

  1. 对象头:markword 8
  2. ClassPointer指针:-XX:+UseCompressedClassPointers 为4字节 不开启为8字节
  3. 实例数据
  1. 引用类型:-XX:+UseCompressedOops 为4字节 不开启为8字节 Oops Ordinary Object Pointers
  1. Padding对齐,8的倍数

3.4 数组对象

  1. 对象头:markword 8
  2. ClassPointer指针同上
  3. 数组长度:4字节
  4. 数组数据
  5. 对齐 8的倍数

3.5 实验

  1. 新建项目ObjectSize (1.8)
  2. 创建文件ObjectSizeAgent
package com.zhou.jvm.objectsize;
import java.lang.instrument.Instrumentation;
/**
 * @author zhouyanxiang
 * @create 2020-08-2020/8/5-17:53
 */
public class ObjectSizeAgent {
    private static Instrumentation instrumentation;
    public static void premain(String agentArgs, Instrumentation inst){
        instrumentation = inst;
    }
    public static long sizeOf(Object o){
        return instrumentation.getObjectSize(o);
    }
}
  1. src目录下创建META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: mashibing.com
Premain-Class: com.mashibing.jvm.agent.ObjectSizeAgent
  1. 注意Premain-Class这行必须是新的一行(回车 + 换行),确认idea不能有任何错误提示
  2. 打包jar文件
    选择Project Structure,然后点击Artifacts,点击+号

  3. 在需要使用该Agent Jar的项目中引入该Jar包 project structure - project settings - library 添加该jar包
  4. 运行时需要该Agent Jar的类,加入参数:
    1
-javaagent:C:\work\ijprojects\ObjectSize\out\artifacts\ObjectSize_jar\ObjectSize.jar
  1. 如何使用该类:
package com.mashibing.jvm.c3_jmm;
import com.mashibing.jvm.agent.ObjectSizeAgent;
public class T03_SizeOfAnObject {
    public static void main(String[] args) {
        System.out.println(ObjectSizeAgent.sizeOf(new Object()));
        System.out.println(ObjectSizeAgent.sizeOf(new int[] {}));
        System.out.println(ObjectSizeAgent.sizeOf(new P()));
    }
    //一个Object占多少个字节
    // -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
    // Oops = ordinary object pointers
    private static class P {
                        //8 _markword
                        //4 _class pointer
        int id;         //4
        String name;    //4
        int age;        //4
        byte b1;        //1
        byte b2;        //1
        Object o;       //4
        byte b3;        //1
    }
}

四、Markword

32位的markword如下图所示

64位的和32位的markword区别如下图所示

Hotspot开启内存压缩的规则(64位机)

  1. 4G以下,直接砍掉高32位
  2. 4G - 32G,默认开启内存压缩 ClassPointers Oops
  3. 32G,压缩无效,使用64位 内存并不是越大越好(-

IdentityHashCode的问题

当一个对象计算过identityHashCode之后,不能进入偏向锁状态

https://cloud.tencent.com/developer/article/1480590https://cloud.tencent.com/developer/article/1484167

https://cloud.tencent.com/developer/article/1485795

https://cloud.tencent.com/developer/article/1482500

对象定位

https://blog.csdn.net/clover_lily/article/details/80095580

  1. 句柄池
  2. 直接指针

对象总结


相关文章
|
25天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
208 1
|
18天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
30 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
12天前
|
机器学习/深度学习 人工智能 缓存
【AI系统】推理内存布局
本文介绍了CPU和GPU的基础内存知识,NCHWX内存排布格式,以及MNN推理引擎如何通过数据内存重新排布进行内核优化,特别是针对WinoGrad卷积计算的优化方法,通过NC4HW4数据格式重排,有效利用了SIMD指令集特性,减少了cache miss,提高了计算效率。
31 3
|
15天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
16天前
|
缓存 监控 算法
Python内存管理:掌握对象的生命周期与垃圾回收机制####
本文深入探讨了Python中的内存管理机制,特别是对象的生命周期和垃圾回收过程。通过理解引用计数、标记-清除及分代收集等核心概念,帮助开发者优化程序性能,避免内存泄漏。 ####
28 3
|
24天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
25天前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
19 3
|
25天前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
45 1
|
1月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
1月前
|
Java Linux Windows
JVM内存
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制。
20 1