基本类型数组(如int[])比包装类数组(如Integer[])性能更优:前者内存连续无碎片、占用更小(400KB vs 2.4MB)、无装箱开销、GC压力低;后者因每个对象独立分配导致严重堆碎片和缓存不友好。

直接把包装类(如 Integer[])换成基本类型数组(如 int[]),配合连续内存布局与访问优化,确实能带来显著性能提升——核心不在“换类型”本身,而在消除对象分散分配、提升缓存效率、降低 GC 压力这三重收益。
用基本类型数组替代包装类数组,彻底避开堆碎片
包装类数组(如 Integer[100000])只分配一个引用数组,但每个 Integer 对象需单独在堆中申请约 24 字节,位置随机。10 万个对象可能散落在几十个内存页上,造成严重碎片:分配慢、GC 扫描成本高、容易触发 Full GC。
而 int[100000] 是一块连续的 400,016 字节内存(对象头 16B + 数据 400,000B),JVM 一次性分配,无碎片、无额外对象头开销、无引用指针跳转。
- 内存占用直降 60%+:10 万
Integer实例 ≈ 2.4 MB;同等数量int仅 400 KB - 避免隐式装箱:循环中
list.add(i)遇到int i→Integer自动装箱,每轮都 new 对象;int[]完全规避 - GC 压力骤减:Young GC 暂停时间缩短,吞吐量明显上升
对齐 + 分块访问,榨干 CPU 缓存性能
连续内存只是基础,还得让 CPU 访问方式匹配硬件特性。主流 CPU 缓存行是 64 字节,一次加载最多覆盖 16 个 int(4 字节 × 16)。
- 起始地址对齐至 64 字节边界(如用
alignas(64)或Unsafe.allocateMemory配合手动偏移),避免单次访问跨缓存行 - 遍历时严格按自然顺序(
i++),保障空间局部性;避免跳跃索引或反向大步长访问 - 超大数组(如千万级)务必分块处理:按 L1 缓存容量(通常 32–64 KB)设定块大小,例如每次处理 8,192 个
int,让热点数据反复命中 L1
配套升级集合与序列化链路
单改数组类型效果有限,需同步优化上下游:
- 集合层:用 FastUtil 的
IntArrayList或 Eclipse Collections 的MutableIntList替代ArrayList<Integer>,底层仍是int[],无装箱、无泛型擦除开销 - 序列化时:DTO 中字段从
Integer age改为int age,Jackson 默认输出"age":0而非"age":null,减少 JSON 字节数;再配合@JsonInclude(NON_DEFAULT)可进一步剔除默认值字段 - 网络传输前:若仍用 JSON,启用 GZIP 压缩;若可改造协议,直接切到 Protobuf,字段定义用
sint32等紧凑类型
注意边界:空值语义不能丢
基本类型无法表达 “未设置” 或 “缺失”,int 默认是 0,易与真实业务值混淆。解决方法有二:
- 业务允许时,约定一个哨兵值(如
-1表示年龄未知),并在读写层统一转换 - 必须保留 null 语义时,改用
OptionalInt(仅适用于低频场景)或拆分为两个字段:int ageValue+boolean isAgeSet


















