system.arraycopy 快是因为 jvm 将其作为本地指令执行,跳过字节码循环和校验开销,但需满足预分配目标数组、非 null 且长度足够等条件;小数据(≤16)不如 for 循环,256 以上才触发向量化优化;倒序搬运防覆盖,禁用 srcpos==destpos 的无效操作。

System.arraycopy 快,不是因为它“写起来简单”,而是 JVM 在底层把它当成本地指令直接执行——它跳过了 Java 字节码循环、每次索引检查、类型校验这些重复开销,直连内存搬运。但这份性能不会自动生效,必须满足几个关键条件。
预分配目标数组,拒绝临时 new
arraycopy 从不负责创建数组,只搬运。传入的 dest 必须是非 null、长度足够的已分配数组。否则先 new 再 copy,等于把 GC 压力和内存分配开销全扛在自己肩上。
- 高频场景(如网络包解析、日志缓冲)建议复用缓冲池:预分配一个大 byte[],按 slot 划分,用 arraycopy 写入指定 offset
- 扩容时务必三步闭环:算新容量 → new 新数组 → arraycopy 搬有效元素(长度是 size,不是 oldLength)
- 避免 Arrays.copyOf:它内部封装了 new + arraycopy,多一次堆分配;已有目标数组时,直接调用更省
长度够大才真正发挥优势
实测表明,拷贝长度 ≤ 16 时,JNI 调用开销常高于简单 for 循环;256 是更稳妥的向量化阈值。JIT 编译器对小数据倾向走精简路径,对大数据才启用 SIMD 或 rep movsq 等硬件指令。
- 建议加运行时分支:if (length
- length 尽量用编译期常量(如 1024),JIT 更易内联、展开、向量化
- packet.length 这类动态值虽不可避免,但可配合固定 buffer size 做截断或填充,提升 predictability
严格类型匹配与内存对齐准备
它不做类型转换,也不容忍擦除干扰。int[] 只能拷到 int[],String[] 可拷到 Object[],但反过来运行时报 ArrayStoreException。同时,能否触发 AVX/SVE 向量指令,取决于源/目标地址是否自然对齐(如 16/32/64 字节)。
- byte[] 缓冲区建议按 16 字节边界分配:new byte[(size + 15) & ~15],再从 offset = 0 或 16 的倍数开始写入
- 避免跨 cache line 搬小块:一次拷贝
- 别用泛型工具中转(如 Arrays.asList().toArray()),擦除后破坏内联机会,降级为普通循环
善用原地重叠拷贝,替代手动方向判断
当 src == dest 时,arraycopy 语义等价于 C 的 memmove:自动根据 destPos 与 srcPos 大小关系决定搬运方向,无需你写两套逻辑。
- 左移(destPos
- 右移(destPos > srcPos):倒序搬运,防止未读数据被提前覆盖
- 典型场景:RingBuffer 数据滚动、ArrayList 删除首元素、切片后原地覆盖
- 禁止 srcPos == destPos 且 length > 0——合法但浪费一次完整校验,纯属无效操作











