当前位置: 首页 > news >正文

内存占用估算方法

优质博文:IT-BLOG-CN

通过掌握每种数据类型的大小,就可以更准确地预测对象和数据的内存消耗。

一、基础数据类型

Java基础数据类型结构,在64位系统开启指针压缩情况下的内存占用字节数:

booleanbytecharshortintlongfloatdouble引用
112248484

这些基础数据类型是轻量级的,应尽可能多地使用他们以减少内存消耗。

二、对象内存占用情况

Java对象的内存占用包括标记字mark word、类指针klass pointer、数据字段(实例变量)以及填充padding

markwordklass pointerdatapadding
84所有字段占用内存之和将内存占用补齐至8的整数倍

由此可见,一个没有任何数据字段的空对象,也会占用16字节的内存空间

三、数组内存占用

数组在Java中是一种特殊类型的对象,它还包括一个额外的数组长度字段。数组的内存占用包括标记字、类指针、数组长度字段、数组元素以及填充。与对象类型,数组的占用长度也必须是8的倍数。需要注意的是,数组元素的大小取决于元素的类型和数量。

markwordklass pointer数组长度字段数组元素padding
844所有字段占用内存之和将内存占用补齐至8的整数倍

四、String对象内存占用

这里,我们以Java8为例说说空String的内存占用情况,我们来看看String类中的成员变量。

/** The value is used for character storage. */
private final char value[];/** Cache the hash code for the string */
private int hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;

根据上面我们对对象和数组内存的分析以及String的成员属性可以得出一个空String对象所占用的内存空间,如下所示。

对象头(8 字节)+ 引用 (4 字节 )  + char 数组(16 字节)+ 1int4字节)+ 1long8字节)= 40 字节

如果String字符串的长度大于0的话,我们也可以得出String占用内存的计算公式,如下所示。

40 + 2 * n

五、内存占用分析工具

位了更准确地估计内存占用情况,我们可以借助一些内存分析工具。
jol-core是一个java官方推出的jar包,地址为GitHub-openjdk/jol

pom依赖:

<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.14</version>
</dependency>

JOL中常用的几个方法:

ClassLayout.parseInstance(obj).toPrintable():查看对象内部的内存布局;
ClassLayout.parseInstance(obj).instanceSize():计算对象的大小,单位为字节;GraphLayout.parseInstance(obj).toPrintable():查看对象外部信息,包括引用的对象;
GraphLayout.parseInstance(obj).totalSize():查看对象占用空间总大小;

注:除了parseInstance(Object obj)外,还有parseClass(Class<?> class),用法基本相同。

代码使用场景:

public class JolTest {public static void main(String[] args) {Object obj = new Test();// 查看对象内部信息System.out.println(ClassLayout.parseInstance(obj).toPrintable());}
}
class Test{private long p;private byte p1;private short p2;
}

六、防止内存膨胀的策略

【1】使用基础类型代替String 在处理业务时,短字符串(如城市三字码)频繁出现。标准String对象在Java中占用至少50字节内存,这对于仅包含2-3个字符的字符串来说是一种浪费。我们可以使用CodeUtil工具将这些字符串编码为原生数据类型,从而显著降低内存占用并可能提升性能。

将字符串编码为浮点数和解码为字符串

public class Main {public static void main(String[] args) {String doubleString = "123.45";// 将字符串编码为浮点数double encodedDouble = CodeUtil.encodeToDouble(doubleString);System.out.println("Encoded Double: " + encodedDouble);// 将浮点数解码为字符串String decodedDoubleString = CodeUtil.decodeFromDouble(encodedDouble);System.out.println("Decoded Double String: " + decodedDoubleString);String input = "Hello, World!";// 使用CodeUtil工具将字符串编码为char[]char[] encodedChars = CodeUtil.encodeToCharArray(input);// 打印编码后的char数组System.out.println("Encoded char array:");for (char c : encodedChars) {System.out.print(c + " ");}}
}

输出:

Encoded Double: 123.45
Decoded Double String: 123.45Encoded char array:
H e l l o ,   W o r l d !

【2】使用对象池: 在某些业务场景中,可能存在大量完全相同或相似的对象。位了减少这些对象的内存占用,可以使用对象池技术来重用这些对象。通过对象池,我们可以确保相同的对象在内存中只有一份拷贝,从而节省大量的内存空间。需要注意的是,在使用对象池技术时,需要确保对象的正确性和线程安全性。

【3】限制容器最大容量: HashMap等容器类在Java中广泛使用,但他们没有容量上限。如果不断向容器中添加元素,它们会持续扩容以及容纳更多的元素,从而导致内存占用不断增加。为了避免这种情况的发生,我们使用具有容量限制的容器类(如Guava Cache)来替代HashMap等无限制容器。这样可以将内存占用控制在一个合理范围内,防止内存膨胀现象的发生。需要注意的是,在设置容量限制时,需要根据实际业务需求和系统性能进行合理权衡。

http://www.lryc.cn/news/453828.html

相关文章:

  • 拓扑排序简介
  • 使用iTextPDF库时,设置文字为中文格式
  • Windows环境下使用Docker配置MySQL数据库
  • 快速上手C语言【上】(非常详细!!!)
  • [深度学习][python]yolov11+deepsort+pyqt5实现目标追踪
  • 【CSDN入门级教程】
  • 二叉搜索树 (BST) 节点插入、查找、删除、获取最大值、最小值和中序遍历排序等功能
  • unity ps 2d animation 蛇的制作
  • 39 C 语言枚举类型、枚举常量、枚举变量、枚举的遍历、枚举数组、枚举与 switch
  • LabVIEW程序怎么解决 Bug?
  • AR智能眼镜之战:Meta vs Snap
  • Spring Boot 集成 Flowable UI 实现请假流程 Demo
  • 毕业设计选题:基于ssm+vue+uniapp的医院管理系统小程序
  • 自动驾驶系列—线控悬架技术:自动驾驶背后的动力学掌控者
  • CTF刷题buuctf
  • Qt QWidget控件
  • 如何通过Dockfile更改docker中ubuntu的apt源
  • [C++][第三方库][jsoncpp]详细讲解
  • JavaScript中decodeURIComponent函数的深入解析与应用指南
  • DMA方式为什么无需保护现场
  • 区块链可投会议CCF C--FC 2025 截止10.8 附录用率
  • springboot系列--web相关知识探索四
  • 在PyQt5中,清空一个QFrame中的所有控件
  • SpringBoot实现:校园资料分享平台开发指南
  • Redis篇(缓存机制 - 基本介绍)(持续更新迭代)
  • 引领5G驱动的全球数字营销革新:章鱼移动广告全球平台的崛起
  • 思维链ChatGPT
  • idea中的Java版本运行错误
  • 用HTML5+CSS+JavaScript庆祝国庆
  • 《OpenCV 计算机视觉》—— 视频背景建模