使用jdk10在Scala中进行不确定的数组复制

sik*_*kor 7 scala compiler-optimization

我使用jdk10运行了我的库的测试,他们在50%的情况下随机失败.我提取了非常小的代码片段来重现错误并在循环计数失败中运行它.1M试验的失败次数通常约为10万至70万.

我到现在才发现:

  1. 代码在jdk8中工作,在jdk9和jdk10中失败
  2. 当您在addressToBytes方法中更改第二行和第三行的顺序时,它可以正常工作
  3. 当你的内联方法SomeOutputStream工作
  4. 禁用最后一级java优化时:-XX:TieredStopAtLevel = 3它可以工作
  5. 在调试模式下运行此代码时,它主要起作用.

我使用scala 2.12.6和javac选项:-source 1.8和-target 1.8.Windows和Linux都会出现此问题.

基本问题是为什么addressToBytes方法并不总是返回相同的结果? 有时代替预期的数组:[4,10,10,10,10]地址的某些部分被替换为0.例如:[4,10,10,10,0]

以下是可用于重现问题的代码:

import java.io.OutputStream
import java.net.InetSocketAddress

object RaceCondition {

  class SomeOutputStream(val data: Array[Byte], var currentIndex: Int) extends OutputStream {
    override def write(bytes: Array[Byte], off: Int, len: Int): Unit = {
      System.arraycopy(bytes, off, data, currentIndex, len)
      currentIndex += bytes.length
    }

    def write(b: Int): Unit = {
      data.update(currentIndex, b.toByte)
      currentIndex += 1
    }
  }

  def addressToBytes(sAddress: InetSocketAddress): Array[Byte] = {
    val result: Array[Byte] = new Array[Byte](sAddress.getAddress.getAddress.length + 1)
    val writer = new SomeOutputStream(result, 0)
    val addressBytes = sAddress.getAddress.getAddress
    writer.write(addressBytes.length)
    writer.write(addressBytes)
    writer.data
  }

  def main(args: Array[String]): Unit = {
    var i = 0
    val expected = Array[Byte](4, 10, 10, 10, 10)
    val address = new InetSocketAddress("10.10.10.10", 1234)
    var count = 0
    var lastOk = true
    while (i < 1000000) {
      i += 1
      val data = addressToBytes(address)
      if (!data.sameElements(expected)) {
        count += 1
        if(lastOk){
          println(s"\n\nBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD $i\n\n")
        }
        lastOk = false
      } else {
        if(!lastOk){
          println(s"\n\nGOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOD $i\n\n")
        }
        lastOk = true
      }
    }
    println(s"Failures: $count")
  }
}
Run Code Online (Sandbox Code Playgroud)