【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
















相关文章
|
1月前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
273 1
|
3天前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
14 3
|
3天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
21 2
|
21天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
26天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
57 1
|
27天前
|
JavaScript
如何使用内存快照分析工具来分析Node.js应用的内存问题?
需要注意的是,不同的内存快照分析工具可能具有不同的功能和操作方式,在使用时需要根据具体工具的说明和特点进行灵活运用。
41 3
|
29天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
1月前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
22 3
|
1月前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
49 1
|
1月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。