System.arraycopy 的性能优势源于跳过 Java 层校验、直连 JVM 内存指令,但仅在数据量大、目标数组已存在、类型干净等条件下释放;小数组(≤16)、未预分配、循环内频繁调用或跨类型搬运时反不如 for 循环。

System.arraycopy 的性能优势不是“天生快”,而是在特定条件下被真正释放出来的——它快,是因为跳过了 Java 层重复校验和字节码解释,直连 JVM 底层内存搬运指令;但它只在你给足条件时才跑出极限速度。
适合用 arraycopy 的典型高性能场景
这些场景共同特点是:数据量可观、目标数组已存在、拷贝逻辑确定、类型干净。
- 高频缓冲区复用:网络协议解析、音视频解码中,预分配固定大小 byte[] 缓冲池,每次用 arraycopy 将 packet payload 写入指定偏移,避免频繁 new 和 GC 压力
- 环形缓冲区(RingBuffer)管理:读指针后仍有未消费数据时,调用 arraycopy 将其前移到缓冲区起始位置腾出头部空间;跨尾部+头部的数据段可用两次调用拼接,比手写循环更安全且易被 JIT 优化
- ArrayList 扩容迁移:底层扩容时 new 更大数组后,整块迁移旧数据——System.arraycopy(src, 0, dest, 0, oldSize) 是标准做法,零对象构造开销
- 算法内原地重排:滑动窗口移动、删除元素后前移、数组旋转等操作,靠 src == dest + 参数顺序控制方向,JVM 自动选择正向或倒序搬运,杜绝覆盖风险
什么时候它反而不如 for 循环?
盲目替换不一定提速,小数据或错误用法会拖慢程序。
- 数组长度 ≤ 16:JNI 调用开销盖过搬运收益,JIT 对极小循环可能直接展开为几条 mov 指令,反而更快
- 目标数组未预分配:Arrays.copyOf 或 clone() 更合适;arraycopy 不负责分配,传 null 或长度不足立刻抛异常
- 在循环体内反复调用:比如每次处理一个 8 字节字段就 call 一次 arraycopy,开销集中在调用本身;应合并为 ≥64 字节再搬
- 跨类型搬运尝试:int[] → long[]、String[] → Integer[] 等,编译不报错,但运行时 ArrayStoreException,且破坏 JIT 内联机会
让 arraycopy 真正跑快的关键细节
性能不只取决于方法本身,更取决于你怎么组织数据和调用方式。
立即学习“Java免费学习笔记(深入)”;
- 基本类型优先:byte[]、int[]、long[] 可触发 SIMD 指令;对象数组只搬引用,虽快但属浅拷贝,需注意语义
- length 尽量用常量:1024 比变量 n 更易被 JIT 内联,尤其在热点路径上
- 内存对齐辅助优化:byte[] 缓冲区按 16 字节边界分配(如 new byte[(size + 15) & ~15]),再从 offset = 0 或 16 倍数开始拷贝,提升向量化概率
- 避免小块跨 cache line:单次拷贝长度小于 64 字节时,JIT 常不启用向量化;必要时合并小段再调用
与 Arrays.copyOf 的分工逻辑
二者不是竞争关系,而是互补封装。
- Arrays.copyOf 用于“需要新数组”的场景:完整复制、扩容(自动填默认值)、缩容(截断),语义清晰,省去手动 new 步骤,内部仍调用 arraycopy
- System.arraycopy 用于“已有目标数组”的场景:部分拷贝、跨数组搬运、同数组原地移位,零分配、零 GC 压力,是唯一能精准控制内存落点的 API
- 不要用 clone() 替代:只能整数组复制,不能指定范围,也不能复用已有数组,且对多维数组仅浅拷贝



















