【JVM原理探索】Java各种类型对象占用内存情况分析

简介: 【JVM原理探索】Java各种类型对象占用内存情况分析

前言


只有当你到了一定层次,需要了解JVM内部运行机制,或者高并发多线程下,你写的代码对内存有影响,你想做性能优化当你想深入了解java对象在内存中,如何存储,或者每个对象占用多大空间时。





内存公式


Java对象的内存布局=对象头(Header)+实例数据(Instance Data)+补齐填充(Padding)




补齐填充


Java对象占用空间是8字节对齐的,即所有Java对象占用bytes数必须是8的倍数




Shallow Size


  1. 对象自身占用的内存大小,不包括它引用的对象。


  1. 针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。


  1. 针对数组类型的对象,它的大小是数组元素对象的大小总和。




Retained Size


Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C,C就是间接引用)


换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存


不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。


image.png




接下来用JProfiler验证:


  1. 新建一个空对象,观察空对象内存占用
public class TestObject {}
复制代码


对象占用内存 16byte,如图:

image.png


结论


一般自建空对象占用内存 16Byte,16byte = 12Byte(Header) + 4Byte(Padding)

  1. 在TestObj中新增一个int属性,观察对象内存占用
public class TestObj {
    private int i;
}
复制代码


对象占用内存16byte,如图

image.png


结论


int 占用 4byte,16byte = 12byte(Header) + 4byte(int)+0byte(padding)

  1. 在TestObj中新增一个 long 属性,观察对象内存占用
public class TestObj {
    private long i;
}
复制代码

对象占用内存 24b,如图

image.png

结论


long 占用 8byte, 24byte = 12(Header) + 8(long) + 4(Padding)

其余基本类型可以参照以上自行验证,原理一样




包装类型占用


  • 包装类(Boolean/Byte/Short/Character/Integer/Long/Double/Float)占用内存的大小 = 对象头大小 + 底层基础数据类型的大小
  • 包装类和其他引用类一样,会产生一个引用(reference)


image.png

  1. 在TestObj中新增一个Integer属性,观察对象内存占用
public class TestObj {
   private Integer  i =128;
}
复制代码

对象占用内存 32b,如图

image.png



结论


Integer 占用16b, 32 = 12 (Header) + 16(Integer) + 4(reference)


特别的:-128~127在常量池,只占用4b,且不产生引用(reference)

  1. 在TestObj中新增一个 Long属性,观察对象内存占用
public class TestObj {
   private Long  l = new Long(1);
}


image.png




结论


Long 占用 24b, 40 = 12 (Header) + 24(Long) + 4(reference)

其余包装类型可以参照以上自行验证,原理一样



基本类型数组占用


64位机器上,数组对象的对象头占用24 bytes,启用压缩后占用16字节。比普通对象占用内存多是因为需要额外的空间存储数组的长度(普通16b-12b)


对象数组本身的大小=数组对象头 + length * 存放单个元素大小

在TestObj中新增一个 char[] 属性,观察对象内存占用

public class TestObj {
   private char[] c = {'a','b','c'};
}
复制代码


char[] c占用内存 40b,如图

image.png



结论


char[3] 占用 24b, 24 = 40 - 16,24 = 16(Header) + 3 * 2(char) + 2(Padding)




封装类型数组占用


封装类型数组比基本类型的数组,需要多管理元素的引用


对象数组本身的大小=数组对象头+length * 引用指针大小 + length * 存放单个元素大小。



在TestObj中新增一个 Integer[] 属性,观察对象内存占用。

public class TestObj {
    private Integer[] i = {128,129,130};
}
复制代码

Integer[] i占用内存 80b,如图

image.png



结论


Integer[3] 占用 80b, 80 = 96 - 16, 80 = 16(Header) + 3 * 4 (reference)+ 3 * 16(Integer) +4(padding)





String占用内存


在TestObj中新增一个空String属性,观察对象内存占用。

public class TestObj {
    private String s = new String("");
}
复制代码

对象占用内存 40b,如图


image.png




结论


String本身占用24byte,24=40-16,也就是说空"",也需要16byte





注意


这里为什么要写String s = new String("")?请自己思考,不写会怎么样?


答:如果写成String s = “”,是不会再堆中开辟内存的,也就看不到String占用的空间,你看到的将会是下面的,至于为什么,都是因为final。


image.png
















相关文章
|
7月前
|
安全 Java 应用服务中间件
Spring Boot + Java 21:内存减少 60%,启动速度提高 30% — 零代码
通过调整三个JVM和Spring Boot配置开关,无需重写代码即可显著优化Java应用性能:内存减少60%,启动速度提升30%。适用于所有在JVM上运行API的生产团队,低成本实现高效能。
932 3
|
6月前
|
Java 大数据 Go
从混沌到秩序:Java共享内存模型如何通过显式约束驯服并发?
并发编程旨在混乱中建立秩序。本文对比Java共享内存模型与Golang消息传递模型,剖析显式同步与隐式因果的哲学差异,揭示happens-before等机制如何保障内存可见性与数据一致性,展现两大范式的深层分野。(238字)
196 4
|
6月前
|
弹性计算 定位技术 数据中心
阿里云服务器配置选择方法:付费类型、地域及CPU内存配置全解析
阿里云服务器怎么选?2025最新指南:就近选择地域,降低延迟;长期使用选包年包月,短期灵活选按量付费;企业选2核4G5M仅199元/年,个人选2核2G3M低至99元/年,高性价比爆款推荐,轻松上云。
713 11
|
6月前
|
存储 缓存 Java
【深入浅出】揭秘Java内存模型(JMM):并发编程的基石
本文深入解析Java内存模型(JMM),揭示synchronized与volatile的底层原理,剖析主内存与工作内存、可见性、有序性等核心概念,助你理解并发编程三大难题及Happens-Before、内存屏障等解决方案,掌握多线程编程基石。
|
7月前
|
缓存 监控 Kubernetes
Java虚拟机内存溢出(Java Heap Space)问题处理方案
综上所述, 解决Java Heap Space溢出需从多角度综合施策; 包括但不限于配置调整、代码审查与优化以及系统设计层面改进; 同样也不能忽视运行期监控与预警设置之重要性; 及早发现潜在风险点并采取相应补救手段至关重要.
937 17
|
11月前
|
Arthas 存储 算法
深入理解JVM,包含字节码文件,内存结构,垃圾回收,类的声明周期,类加载器
JVM全称是Java Virtual Machine-Java虚拟机JVM作用:本质上是一个运行在计算机上的程序,职责是运行Java字节码文件,编译为机器码交由计算机运行类的生命周期概述:类的生命周期描述了一个类加载,使用,卸载的整个过类的生命周期阶段:类的声明周期主要分为五个阶段:加载->连接->初始化->使用->卸载,其中连接中分为三个小阶段验证->准备->解析类加载器的定义:JVM提供类加载器给Java程序去获取类和接口字节码数据类加载器的作用:类加载器接受字节码文件。
960 55
|
Arthas 监控 Java
Arthas memory(查看 JVM 内存信息)
Arthas memory(查看 JVM 内存信息)
958 6
|
6月前
|
存储 缓存 Java
我们来说一说 JVM 的内存模型
我是小假 期待与你的下一次相遇 ~
504 5
|
6月前
|
存储 缓存 算法
深入理解JVM《JVM内存区域详解 - 世界的基石》
Java代码从编译到执行需经javac编译为.class字节码,再由JVM加载运行。JVM内存分为线程私有(程序计数器、虚拟机栈、本地方法栈)和线程共享(堆、方法区)区域,其中堆是GC主战场,方法区在JDK 8+演变为使用本地内存的元空间,直接内存则用于提升NIO性能,但可能引发OOM。
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
2606 1