system.arraycopy高效复制大数组的关键在于jvm直接调用底层内存搬运,不分配内存、不走字节码循环;需确保目标数组容量充足、类型严格匹配、避免泛型擦除、大数组(≥256)才启用,原地复制自动保序,多线程写同一dest须隔离。

System.arraycopy 能高效复制大体积数组,关键不在“怎么写那行代码”,而在于让 JVM 顺利进入底层内存块搬运路径——它不分配内存、不走字节码循环、只做地址级平移。一旦参数失当或环境不匹配,优势立刻消失,甚至比 for 循环还慢。
目标数组必须提前配足容量,且类型严格匹配
它不做扩容,也不做类型转换。复制前必须确保:
- dest 数组已存在,且长度 ≥ destPos + length;少一个元素就抛 ArrayIndexOutOfBoundsException
- src 和 dest 元素类型兼容:int[] 只能拷到 int[],String[] 可拷到 Object[],但反过来或跨基本类型(如 int[] → long[])会直接报 ArrayStoreException
- 避免泛型包装调用:用 Arrays.asList().toArray() 或泛型工具方法中转,会擦除类型、引入桥接逻辑,破坏 JIT 内联机会
大数组才值得用,小数据反而拖后腿
实测表明,拷贝长度 ≤ 16 时,JNI 调用开销常高于简单赋值;256 是更稳妥的启用阈值:
- length 尽量用编译期可判定的常量(如 1024),JIT 更易向量化或展开为 SIMD 指令
- 若 length 是运行时变量(如 packet.length),建议加分支判断:小包走 for,大包走 arraycopy
- 基本类型数组(byte[]、int[])性能最优;对象数组拷的是引用,快但后续修改会影响源,这是浅拷贝本质,不是 bug
原地迁移要防覆盖,重叠区间由 JVM 自动保序
当 src == dest 时(如 RingBuffer 前移未读数据),是否安全不取决于你写法,而取决于 srcPos 与 destPos 的相对大小:
- destPos > srcPos(右移):JVM 自动倒序搬运,避免中间值被覆盖
- destPos
- 别手动拆成两段 or 加锁——它本身已按 memmove 语义实现,重复干预反而引入开销和风险
多线程写同一 dest 数组必须隔离
单次 arraycopy 调用是原子的,但不保证线程安全:
- 多个线程往同一数组不同区域写(如 thread-1 写 [0,999],thread-2 写 [1000,1999]),仍可能因 CPU 缓存未及时同步导致撕裂
- 推荐做法:每个线程操作独立 buffer,最后用一次 arraycopy 合并;或采用“新数组 + AtomicReference.lazySet”模式替换引用
- 绝对不要在无锁场景下让多线程并发调用 arraycopy 到同一个 dest











