System.arraycopy 是 Java 中最底层、最高效的数组拷贝方式,由 JVM 调用 native 代码(如 memcpy/memmove)实现,避免字节码边界检查、GC 干扰和解释开销,支持重叠安全复制,但要求参数严格合法。

System.arraycopy 是 Java 中最底层、最高效的数组拷贝方式,它不经过 Java 层的循环逻辑,而是直接由 JVM 调用本地(Native)代码实现,通常映射到 C/C++ 的内存操作函数(如 memmove 或 memcpy),因此性能远超手动 for 循环或 Arrays.copyOf 等封装方法。
为什么 System.arraycopy 比 for 循环快?
Java 字节码中,每次数组读写(aaload/aastore)都需做边界检查和类型校验。for 循环每迭代一次,这些检查就执行一次;而 System.arraycopy 在 JNI 层一次性完成全部校验(如源/目标数组非空、索引合法、长度非负、类型兼容等),之后直接调用高度优化的内存复制指令,避免了重复开销。
- 无解释执行开销:JVM 可对 native 方法做内联或直接委托给 CPU 的块复制指令(如 x86 的
rep movsb) - 避免 GC 干扰:批量操作减少写屏障触发频次(尤其在老年代对象间拷贝时)
- 支持跨代/跨区域复制:HotSpot 中可绕过部分卡表(Card Table)更新逻辑(取决于 GC 算法)
底层调用链的关键路径(HotSpot JVM 示例)
从 Java 调用到最终内存操作,典型流程如下:
- Java 层调用
System.arraycopy(src, srcPos, dest, destPos, length) - JVM 查找并跳转到注册的 native 方法入口:
JVM_ArrayCopy(位于hotspot/src/share/vm/prims/jvm.cpp) - 根据数组类型(对象/基本类型)、是否同类型、是否重叠,选择具体复制函数:
copy_array→typeArrayOopDesc::copy_array或objArrayOopDesc::copy_array - 最终调用平台相关汇编 stub(如
copy_memory),使用memcpy(无重叠)或memmove(可能重叠)语义
注意:当源与目标为同一数组且区间重叠时(如 arraycopy(arr, 0, arr, 1, 5)),JVM 自动选用安全的前向/后向拷贝策略,保证语义正确 —— 这是手动 memcpy 容易出错的地方。
使用时必须注意的边界条件
虽然高效,但 System.arraycopy 对参数极其敏感,任何非法输入都会立即抛出运行时异常,且不提供默认容错:
-
src 或 dest 为
null→ 抛NullPointerException -
length < 0 → 抛
NegativeArraySizeException -
srcPos < 0、destPos < 0、srcPos + length > src.length、destPos + length > dest.length → 抛
ArrayIndexOutOfBoundsException - 源数组与目标数组类型不兼容(如将
String[]拷入Integer[])→ 抛ArrayStoreException(运行时检查,非编译期)
替代方案对比:什么情况下不该用它?
并非所有场景都适合直接调用 System.arraycopy:
- 需要深拷贝对象数组时:它只复制引用,不会递归克隆元素对象
- 目标数组需动态扩容:应优先用
Arrays.copyOf(内部仍调用 arraycopy,但自动分配新数组) - 需过滤、转换或并发安全:它不支持 lambda 或原子操作,此时 Stream 或
Collections.copy更合适 - 跨 JVM 语言互操作(如 GraalVM Native Image):部分 native 方法可能受限,需确认 Substrate VM 支持情况
真正发挥其价值的场景是:已知数组大小、类型明确、追求极致吞吐(如 NIO buffer 处理、序列化框架、高性能集合实现)。

















