System.arraycopy是JVM内置内存块搬运原语,非万能复制函数;其高效前提为目标数组预分配且容量充足、源目标类型字节级兼容、长度≥256并严格校验参数,否则可能比for循环更慢且易抛异常。

System.arraycopy 不是“复制函数”,而是 JVM 内置的内存块搬运原语——它快,是因为跳过 Java 层循环和逐元素校验;它稳,前提是迁移前把数据生命周期理清楚。大规模数组迁移不出错、不降速,关键不在调用那行代码,而在参数对齐、容器就位、类型守界。
目标数组必须提前配齐,且容量刚够
arraycopy 从不分配内存,也不扩容。它只搬数据,不造容器。所以迁移前必须确保:
- dest 数组已存在,且 destPos + length ≤ dest.length;少一个位置就抛 ArrayIndexOutOfBoundsException
- src 数组同理:srcPos + length ≤ src.length,否则同样越界中断
- 避免用 Arrays.copyOf() 替代——它会 new 新数组,触发 GC,对百兆级以上数组尤其危险
- 典型做法:网络收包复用固定缓冲区(如 byte[65536]),每次只用 arraycopy 搬 payload 到偏移 0 处
源与目标类型必须字节级兼容
它不做类型推导、不隐式转换、不拆箱装箱,只做内存平移。兼容性由 JVM 运行时强校验:
- int[] → int[] ✅,byte[] → byte[] ✅,String[] → Object[] ✅(协变允许)
- int[] → long[] ❌,Integer[] → int[] ❌,Object[] → String[] ❌ —— 全部报 ArrayStoreException
- 基本类型数组最快:无 GC write barrier,JVM 可直发 SIMD 指令
- 对象数组只拷引用:快,但后续修改对象会影响源数组,这是浅拷贝本质
参数必须运行前校验,小数据别硬套
五个参数(src, srcPos, dest, destPos, length)任意一个失当,立刻抛异常。实测表明:
立即学习“Java免费学习笔记(深入)”;
- length ≤ 16 时,JNI 调用开销常高于简单 for 循环,反而更慢
- 64 是性能拐点,256 是推荐启用下限;建议加分支判断:if (len
- length 尽量用编译期常量(如 1024),JIT 更易内联、向量化或启用 SIMD
- 务必封装工具方法,用 Objects.requireNonNull() 防 null,Math.min() 控制 length 上限
原地重排自动保序,但方向靠你定
当 src == dest 时,就是内存重排(如 RingBuffer 前移、ArrayList 删除后前挪)。JVM 会根据 srcPos 与 destPos 关系自动选择正向或倒序搬运,避免覆盖:
- destPos < srcPos(左移):如 System.arraycopy(arr, 4, arr, 2, 5),JVM 正向搬,安全
- destPos > srcPos(右移):如 System.arraycopy(arr, 2, arr, 5, 5),JVM 倒序搬,防中间值丢失
- destPos == srcPos:等效空操作(length ≠ 0);length = 0 则只做边界校验,常用于预检
- 切忌手动拆成两段或加锁干预——它本身按 memmove 语义实现,多此一举反而引入风险


















