导读:本期聚焦于小伙伴创作的《一个空的ArrayList到底占用多少字节?Java集合内存占用该怎么分析》,敬请观看详情。想搞清楚Java里一个空ArrayList占多大内存,不能只凭感觉猜。对象头、引用数组与对齐填充共同决定了实际大小。用JOL工具打印布局会发现,在开启普通对象指针压缩的64位虚拟机中,空ArrayList实例自身约占用二十四字节,而内部那个长度为零的elementData数组对象还要再占十六字节。若关闭压缩则实例与数组都会变大。理解这些细节能帮助我们在高并发或海量小集合场景下评估真实堆压力,而不是盲目认为集合“很轻量”。

在Java开发中,集合是使用频率极高的基础组件,但很多人对它们在堆内存中的真实开销并没有清晰概念。以ArrayList为例,哪怕里面一个元素都没有,它在内存里也并不是“零成本”存在的。要准确回答一个空的ArrayList占用多少字节,我们需要从对象内存布局的底层规则说起。

一个空的ArrayList到底占用多少字节?Java集合内存占用该怎么分析

Java对象的内存布局基础

在HotSpot虚拟机中,一个Java对象在堆里的存储结构通常分为三个部分:对象头(Object Header)、实例数据(Instance Data)和对齐填充(Padding)。对象头在64位虚拟机上,如果开启了普通对象指针压缩(UseCompressedOops,默认开启),会占用12字节;如果关闭压缩则占用16字节。实例数据就是我们在类里定义的那些字段,比如ArrayList里的elementData数组引用和size整型。对齐填充是为了让对象大小是8字节的整数倍而补上的空位。

对于ArrayList而言,它的源码里核心字段其实很少,主要就是transient Object[] elementData和一个private int size。在压缩指针模式下,一个对象引用占4字节,一个int占4字节,因此实例数据部分共8字节。加上12字节对象头,已经20字节,再按8字节对齐补4字节,ArrayList对象本身至少24字节。但这还没算elementData指向的那个数组对象。

空ArrayList中数组对象的开销

当我们执行new ArrayList<>()时,构造函数内部会用一块空数组来初始化elementData。在JDK 8及之后,无参构造通常指向一个共享的空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA,但在某些版本或第一次扩容前,它仍可能是一个独立的长度为0的Object数组。一个长度为0的数组对象,其对象头同样12字节(压缩指针),加上4字节的数组长度字段,共16字节,且已经对齐,无需填充。

因此,如果我们把ArrayList对象本身和它所引用的那个空数组都算上,在压缩指针的64位JVM里,一个“独立”的空ArrayList实际占用的堆内存大约是24加16等于40字节。如果使用的是JDK默认共享空数组,则数组不归该实例独有,但概念模型上仍应意识到数组对象本身有成本。下面的代码可以直观地打印出真实布局。

import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;

public class MemoryTest {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        // 打印ArrayList对象自身的内存布局
        System.out.println(ClassLayout.parseInstance(list).toPrintable());
        // 打印其内部elementData数组的内存布局
        System.out.println(ClassLayout.parseInstance(list.toArray()).toPrintable());
    }
}

用JOL工具做准确测量

JOL(Java Object Layout)是OpenJDK提供的官方工具,能够直接输出对象在内存中的字段偏移与占用情况。在Maven项目中引入jol-core依赖后,就可以像上面代码那样调用ClassLayout。运行结果会明确显示对象头大小、每个字段的偏移量以及总的占用字节数,比任何文字推算都可靠。

当我们关闭指针压缩,即添加JVM参数-XX:-UseCompressedOops时,对象头变为16字节,引用变为8字节,ArrayList实例数据变为12字节(8加4),对齐后实例共32字节;数组对象头16字节加长度4字节再对齐到24字节。此时一个空ArrayList关联的内存会明显上涨。这也提醒我们,在容器环境或超大堆场景下,指针压缩的开关会直接影响集合的整体内存 footprint。

JVM模式ArrayList实例空数组对象合计估算
压缩指针(默认)24字节16字节40字节
关闭压缩32字节24字节56字节

为什么需要关心这点开销

单个空ArrayList看起来只有几十字节,似乎微不足道。但在真实系统中,我们经常会创建成千上万个小型集合,例如每次请求都new一个ArrayList作为临时容器,或者在缓存里用Map套List存储稀疏数据。此时几十字节乘以百万级数量,就会变成几十MB甚至上百MB的隐性堆占用。理解其构成有助于我们选择合适的初始化方式,比如复用空集合常量、使用原始类型集合库,或在特定场景改用数组。

另外,在做内存调优或排查Full GC频繁的问题时,很多开发者只盯业务对象,却忽略了框架内部大量细碎集合的累积效应。通过对ArrayList内存占用的分析,我们可以建立起“对象头加引用加数组”的评估习惯,进而推广到HashMap、LinkedList等其它集合,形成系统的Java内存透视能力。

小结

一个空的ArrayList在常见64位JVM压缩指针模式下,对象本身约24字节,若计入独立的空数组对象则共约40字节;关闭指针压缩后相应增至32加24约56字节。借助JOL工具,我们能抛开猜测,用数据看清每一份内存去向,这比记住某个数字更有价值。

ArrayList内存占用JOL工具修改时间:2026-08-02 10:06:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。