循环展开优化

循环展开(Loop Unrolling)是一种减少循环控制开销的技术,通过减少循环次数、增加每次迭代的工作量来提升性能。适用于循环体简单且迭代次数固定的场景。

示例代码:未展开的循环

for (int i = 0; i < 100; i++) {
    sum += array[i];
}

展开后的循环(4次展开)

for (int i = 0; i < 100; i += 4) {
    sum += array[i];
    sum += array[i+1];
    sum += array[i+2];
    sum += array[i+3];
}

优化效果

  • 减少分支预测失败次数
  • 降低循环索引计算开销
  • 可能触发编译器自动向量化

注意事项

  • 展开次数需适中(通常2-8次)
  • 剩余迭代需单独处理(若总数非展开倍数)
  • 可能增加代码体积,需权衡缓存影响

内存访问优化

内存访问模式对性能影响显著,优化目标是提升缓存命中率、减少内存延迟。

1. 顺序访问优于随机访问

  • 顺序访问可触发预取机制
  • 示例:优先遍历一维数组而非链表

2. 空间局部性优化

// 低效:列优先访问二维数组
for (int col = 0; col < N; col++) {
    for (int row = 0; row < M; row++) {
        sum += matrix[row][col];
    }
}

// 高效:行优先访问(与内存布局一致)
for (int row = 0; row < M; row++) {
    for (int col = 0; col < N; col++) {
        sum += matrix[row][col];
    }
}

3. 数据对齐

  • 对象大小尽量为2^n字节
  • 使用@Contended注解避免伪共享(Java 8+)
  • modelscope.cn/learn/71489
    modelscope.cn/learn/71488
    modelscope.cn/learn/71485
    modelscope.cn/learn/71484
    modelscope.cn/learn/71482
    modelscope.cn/learn/71480
    modelscope.cn/learn/71478
    modelscope.cn/learn/71476
    modelscope.cn/learn/71474
    modelscope.cn/learn/71472
    modelscope.cn/learn/71470
    modelscope.cn/learn/71469
    modelscope.cn/learn/71466
    modelscope.cn/learn/71465
    modelscope.cn/learn/71462

4. 对象复用

  • 避免频繁创建小对象
  • 使用对象池或线程局部变量

复合优化策略

循环展开+内存预取

final int CHUNK = 4;
for (int i = 0; i < array.length; i += CHUNK) {
    // 手动预取下个块
    if (i + CHUNK < array.length) {
        Prefetch.access(array, i + CHUNK);
    }
    
    // 展开处理当前块
    sum += array[i];
    sum += array[i+1];
    sum += array[i+2];
    sum += array[i+3];
}

工具辅助

  • 使用JMH进行微观基准测试
  • 通过JITWatch分析热点代码
  • 检查-XX:+PrintAssembly输出的汇编指令

注意事项

  • 优先使用System.arraycopy()而非手动循环拷贝
  • 对于边界检查,JVM会优化简单循环的边界检查
  • 避免在循环内调用length方法(缓存到局部变量)
  • 考虑使用Arrays.fill()等内置优化方法

更多推荐