system.arraycopy不是“写对就能快”的工具,其性能优势仅在数组≥256、基本类型、目标已预分配等条件匹配时释放;参数任一错误即抛异常,小数组(≤16)反不如for循环,且必须严格校验五参数边界。

System.arraycopy 不是“写对就能快”的工具,它的性能优势只在条件匹配时才释放——核心在于跳过 Java 层循环和检查,直连 JVM 底层内存搬运指令。但参数错一个就崩溃,小数组反而更慢,用错场景甚至拖累整体吞吐。
五参数必须全对齐,越界立刻抛异常
调用格式固定为:System.arraycopy(src, srcPos, dest, destPos, length),五个参数缺一不可,且全部在运行时校验:
- src 和 dest 都不能为 null,否则直接抛 NullPointerException
- srcPos ≥ 0 且 srcPos + length ≤ src.length,否则 ArrayIndexOutOfBoundsException
- destPos ≥ 0 且 destPos + length ≤ dest.length,越界同样崩
- length 可为 0(合法,可用于边界预检,零开销)
- 所有参数必须在调用前手动校验,尤其当 from/to 来自用户输入或配置文件时
什么时候真快?看长度、类型和内存布局
快不是默认状态,而是特定组合下的结果:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 基本类型数组(int[]、byte[] 等)拷贝 ≥ 256 元素时优势明显:JVM 可启用 SIMD 指令批量搬运
- 对象数组(String[]、MyBean[])也快,但只复制引用:不触发 GC 写屏障,适合高吞吐场景
- 长度 ≤ 16 的数组,for 循环通常更快:JNI 调用开销盖过了搬运收益
- 目标数组必须已分配且容量充足:arraycopy 不负责 new,传入的 dest 必须是非 null、长度足够的数组
- 避免跨 cache line 小块搬运:单次 length
原地重排不用手写方向判断,靠参数自动保安全
当 src == dest 时,arraycopy 自动按 memmove 语义处理重叠区域,无需 if 分支判断左右移:
- 左移(destPos :如 System.arraycopy(arr, 5, arr, 3, 5),JVM 正向执行,不会覆盖未读数据
- 右移(destPos > srcPos):如 System.arraycopy(arr, 0, arr, 3, 5),JVM 倒序搬运,先搬高地址再覆盖低地址
- 边界贴线也安全:System.arraycopy(arr, 7, arr, 6, 3) 把 [7,8,9] 搬到 [6,7,8],destPos + length == 9,不越界即可
- 禁止 srcPos == destPos 且 length > 0:这是无效搬运,无意义且浪费
高频场景必须复用缓冲区,别让 GC 成瓶颈
真正影响吞吐的往往不是拷贝本身,而是频繁分配与回收:
- 网络协议解析、RingBuffer、日志切片等场景,应预分配 byte[] 缓冲池,按 slot 划分,用 arraycopy 精准写入偏移位置
- 避免循环中 new 小数组:例如每次解析 packet 都 new byte[2048] → 触发 Young GC,停顿明显
- 固定长度截取可复用 buffer:先 System.arraycopy(src, offset, buffer, 0, actualLen),再 Arrays.copyOf(buffer, actualLen)
- 扩容类操作(如 ArrayList)优先用 arraycopy 整块迁移:比逐个 add 或 Stream.collect 更轻量
- 多线程写同一 dest 数组必须隔离:arraycopy 单次原子,但不保证缓存一致性;推荐各线程独立 buffer,最后合并
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










