System.arraycopy更快,因其绕过Java层运行时约束,一次性校验后直接调用JVM底层内存搬运指令(如memmove或SIMD),避免了手动循环的重复边界检查、类型校验与字节码解释开销。

System.arraycopy 是 Java 中唯一能绕过 Java 层运行时约束、直接触发 JVM 底层内存块搬运的原语。它的效率不来自“写得更聪明”,而来自彻底跳过解释执行、边界检查和循环控制——本质上是把一段连续内存当作整体交给 CPU 指令(如 memmove 或 SIMD 优化路径)处理。
为什么它快:不是语法糖,是执行路径降维
手动 for 循环每次迭代都要:
- 查源数组长度、比对索引是否越界
- 查目标数组长度、再比对一次索引
- 若为引用类型,还要做 null 检查和类型校验(比如
Object[] → String[]会在第一个非 String 元素处失败) - JVM 解释执行条件判断、跳转、栈帧维护
而 System.arraycopy 在进入 native 前一次性完成全部参数校验(非空、索引合法、长度非负、类型兼容),之后直接调用内存搬运函数,中间不经过任何 Java 字节码。
真正决定速度的三个底层因素
它的性能表现取决于硬件与 JVM 协同程度:
- CPU 缓存友好性:顺序流式读写,完美匹配 L1/L2 缓存预取机制;for 循环中离散的读+写容易反复驱逐 cache line
- 指令级优化:HotSpot 对其做了专项 JIT 优化——自动内联为紧凑汇编、启用 AVX 等 SIMD 指令(一次搬 16/32 字节)、减少写屏障开销
-
内存带宽利用率:对
byte[]等基础类型,常逼近硬件memcpy极限带宽;对象数组则受 GC 卡表更新策略影响,优势略打折扣
什么时候快得明显?临界点很实在
性能优势不是线性的,而是随数组规模跃升:
- 长度 < 4:for 循环可能更快——JVM 启动成本 > 拷贝收益,小数组易被 JIT 栈上分配优化
- 长度 20–1000:arraycopy 开始稳定胜出,优势随长度增长加速扩大
- 长度 > 10⁵:差距可达 3–5 倍;复制 1GB
int[](约 2.5 亿元素)在主流服务器上通常需 20–80ms,无法压缩到毫秒级,但已是软件层最优解
怎么让它跑出极限速度?关键约束不能漏
脱离这些条件,它可能比手写 for 还慢:
- 必须是同类型数组(
int[] → int[]、String[] → Object[]可,int[] → long[]不行) - 避免频繁调用小数组——JNI 调用开销会抵消收益
- 重叠拷贝(同一数组内移位)时,依赖
srcPos与destPos关系触发 JVM 自动选择正向/倒序执行,无需手动干预 - 基本类型数组最稳;对象数组若涉及跨代引用(老年代 → 新生代),仍要走写屏障,加速有限


















