基本类型存储效率高、引用类型开销大,因前者栈中存值、无gc压力,后者栈中存地址、数据在堆中且需gc管理;数组、string、包装类均为重量级引用类型,误用易致oom。

基本类型存储效率高,引用类型开销大——这不是理论推导,而是JVM实际运行中可测量的差异。关键不在“是不是对象”,而在“数据怎么放、谁来管、何时清”。
栈里存值 vs 栈里存地址
基本类型(如 int、char、boolean)声明后,JVM直接在栈帧的局部变量表中分配固定空间:int 恒占4字节,char 固定2字节,boolean 实际按1字节对齐。这个值就是数据本身,读写一次内存就完成。
引用类型(包括 String、ArrayList、int[]、甚至 Integer)的变量,栈中只存一个地址(通常4或8字节),真正的数据全在堆里。哪怕是一个空 new Object(),HotSpot JVM 也要分配约16字节堆空间——含对象头(Mark Word + 类指针)、对齐填充,远超一个 int 的4字节。
没有GC压力 vs 频繁触发GC
基本类型随方法退出自动出栈,不参与垃圾回收。而每个引用类型对象都得由GC追踪:
- 循环中反复 new ArrayList 或 StringBuilder,会快速填满 Young 区,引发频繁 Minor GC
- 短生命周期包装类(如 Integer i = 1000)无法命中缓存(-128~127),每次都是新对象
- 字符串拼接(s += "x")生成大量中间 String 对象,加剧堆碎片
实测显示:用 int[] 替代 ArrayList
看似“轻量”的引用类型陷阱
有些类型容易被误当成基本类型用,实际却是重量级引用:
- 所有数组都是引用类型:即使 int[] nums,变量 nums 存的是地址,整个数组对象(含元素+头信息)都在堆中
- String 不可变:每次 substring、concat、replace 都新建对象,不是修改原内容
- 包装类不是基本类型别名:Long 和 long 内存模型完全不同,前者带完整对象头和GC生命周期
在滑动窗口、DFS回溯、前缀和等算法中,这类误用常导致对象数量爆炸,轻则延迟升高,重则直接 OOM。
提升存储效率的实用选择
不改算法逻辑,只换数据载体,就能显著压低内存 footprint:
- 优先用 int[]、boolean[],而非 ArrayList
或 HashSet - 需要动态扩容时,给 ArrayList 预设初始容量,避免多次 resize 导致数组复制
- 字符处理用 char[] 或 StringBuilder,禁用链式 String +
- 复杂状态不用 Node 对象数组,改用多个平行基本数组:int[] x, int[] y, boolean[] visited
这些调整直击内存分配本质,让数据真正“轻装上阵”。











