【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
















相关文章
|
15天前
|
监控 算法 Java
Java中的内存管理:理解Garbage Collection机制
本文将深入探讨Java编程语言中的内存管理,特别是垃圾回收(Garbage Collection, GC)机制。我们将从基础概念开始,逐步解析垃圾回收的工作原理、不同类型的垃圾回收器以及它们在实际项目中的应用。通过实际案例,读者将能更好地理解Java应用的性能调优技巧及最佳实践。
55 0
|
9天前
|
存储 缓存 Java
java线程内存模型底层实现原理
java线程内存模型底层实现原理
java线程内存模型底层实现原理
|
4天前
|
存储 算法 Java
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
本文介绍了 JVM 的内存区域划分、类加载过程及垃圾回收机制。内存区域包括程序计数器、堆、栈和元数据区,每个区域存储不同类型的数据。类加载过程涉及加载、验证、准备、解析和初始化五个步骤。垃圾回收机制主要在堆内存进行,通过可达性分析识别垃圾对象,并采用标记-清除、复制和标记-整理等算法进行回收。此外,还介绍了 CMS 和 G1 等垃圾回收器的特点。
14 0
深入解析 Java 虚拟机:内存区域、类加载与垃圾回收机制
|
11天前
|
Java 编译器
深入理解Java内存模型:从基础到高级
本文旨在通过通俗易懂的方式,引导读者深入理解Java内存模型(JMM)的核心概念和工作原理。我们将从简单的基础知识入手,逐步探讨重排序、顺序一致性问题以及volatile关键字的实现机制等高级主题。希望通过这篇文章,你能够对Java内存模型有一个清晰、全面的认识,并在实际编程中有效地避免并发问题。
|
9天前
|
存储 算法 Java
深入理解Java内存管理
本文将通过通俗易懂的语言,详细解析Java的内存管理机制。从JVM的内存结构入手,探讨堆、栈、方法区等区域的具体作用和原理。进一步分析垃圾回收机制及其调优方法,最后讨论内存泄漏的常见场景及防范措施。希望通过这篇文章,帮助读者更好地理解和优化Java应用的内存使用。
|
13天前
|
监控 算法 Java
Java中的内存管理与垃圾回收机制
本文将深入探讨Java编程语言中的内存管理方式,特别是垃圾回收(Garbage Collection, GC)机制。我们将了解Java虚拟机(JVM)如何自动管理内存,包括对象创建、内存分配以及不使用对象的回收过程。同时,我们还将讨论不同的垃圾回收算法及其在不同场景下的应用。
|
12天前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
19天前
|
监控 算法 Java
Java中的内存管理:理解垃圾回收机制的深度剖析
在Java编程语言中,内存管理是一个核心概念。本文将深入探讨Java的垃圾回收(GC)机制,解析其工作原理、重要性以及优化方法。通过本文,您不仅会了解到基础的GC知识,还将掌握如何在实际开发中高效利用这一机制。
|
19天前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理策略和垃圾回收机制。首先介绍了Java内存模型的基本概念,包括堆、栈以及方法区的划分和各自的功能。进一步详细阐述了垃圾回收的基本原理、常见算法(如标记-清除、复制、标记-整理等),以及如何通过JVM参数调优垃圾回收器的性能。此外,还讨论了Java 9引入的接口变化对垃圾回收的影响,以及如何通过Shenandoah等现代垃圾回收器提升应用性能。最后,提供了一些编写高效Java代码的实践建议,帮助开发者更好地理解和管理Java应用的内存使用。
|
2月前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
下一篇
无影云桌面