【问题标题】:Can bounds checking be disabled in Java/Scala?可以在 Java/Scala 中禁用边界检查吗?
【发布时间】:2017-03-02 12:20:12
【问题描述】:

我们知道,Java 在每次访问数组元素时都会检查索引是否超出范围。但在某些情况下,例如 Scala 中的映射函数,编译器/库会自己处理索引,从而保证不会越界访问。

那么,出于性能原因,是否可以在 JVM 中对代码的某些部分禁用此类边界检查?

【问题讨论】:

  • 边界检查很少是实际的性能瓶颈,因为它被高度优化(至少循环提升)。如果您已完成指令级分析以确认确实如此,那么您可以考虑使用Unsafe 绕过检查。但据我所知,没有一个 JDK 类会做这样的事情,只有少数 3rd-party 高性能库可能。
  • @the8472 JDK 确实经常使用 Unsafe,例如hg.openjdk.java.net/jdk8/jdk8/jdk/file/tip/src/share/classes/… 本来打算只用的,后来第三方库也查了 Unsafe。
  • @Kan CHM 使用 unsafe 进行并发(对字段的原子访问),我们正在讨论使用 unsafe 绕过数组中的边界检查
  • @the8472 无论如何,请参见 ArraySupport 类,它被 java.util.Arrays github.com/netroby/jdk9-dev/blob/master/jdk/src/java.base/share/… 使用,也 nio XxxBuffer 非常依赖 Unsafe。公共 API 只是将 Unsafe 方法与额外的检查一起包装以使其安全。
  • @kan 他们使用 unsafe 来访问堆外数据,您总是必须手动进行偏移计算。本次讨论是关于通过 Unsafe 访问 java 数组(即堆上)并且根本不进行任何边界检查以消除进行边界检查的微小成本。通常编译器无论如何都非常擅长将那些提升出循环,这就是为什么很少有需要这种优化的情况,我认为你不会在 JDK 中找到。

标签: java arrays scala memory-management jvm


【解决方案1】:

不,不能禁用数组范围检查。那会使 JVM 变得不安全。

但是,JIT 编译器可能会推断出某些范围检查是不必要的,并将它们优化掉。

此外,JIT 编译器可能会为某些内置类型做“聪明的事情”。您可以通过在本机代码中实现一些东西来回避这个问题,但您可能会发现进行本机调用的开销超过了本机进行计算所节省的成本。


您能否展示一些示例代码,其中 JIT 推断不需要边界检查?

并非没有花费比我愿意的时间更多的时间 :-)

然而,JIT 编译器理论上可以推断这里不需要数组边界检查:

  public int sum(int[] array) {
      int sum = 0;
      for (int i = 0; i < array.length; i++) {
          sum += array[i];
      }
      return sum;
  }

在这种情况下,简单的窥视孔优化应该消除循环体中的第二次边界检查:

  public int sum2(int[] array) {
      int sum = 0;
      for (int i = 0; i < array.length; i++) {
          sum += array[i];
          sum += array[i];
      }
      return sum;
  }

【讨论】:

  • 您能否展示一些示例代码,其中 JIT 会推断不需要边界检查?
猜你喜欢
  • 1970-01-01
  • 2013-09-23
  • 2010-09-19
  • 2011-05-27
  • 1970-01-01
  • 2011-06-14
  • 2014-05-14
  • 2017-04-09
相关资源
最近更新 更多