Java 如何在String.valueOf(int)中实现ArrayOutOfBoundsException?

Java 如何在String.valueOf(int)中实现ArrayOutOfBoundsException?,java,jvm,java-8,jvm-hotspot,Java,Jvm,Java 8,Jvm Hotspot,为什么此代码有时会生成BoundsException数组?对于String.valueOf(int),这怎么可能呢 更新 我不知道发生这种情况时字节的值,但似乎不可能有任何可能的字节值 一旦发生一次,每次调用都会出现相同的异常 环境: 我可以用以下代码可靠地重现您的问题: public class Main { public static StringBuilder intToString(byte[] bs) { final StringBuilder sb = new Strin

为什么此代码有时会生成BoundsException数组?对于
String.valueOf(int)
,这怎么可能呢

更新

我不知道发生这种情况时字节的值,但似乎不可能有任何可能的字节值

一旦发生一次,每次调用都会出现相同的异常

环境:


我可以用以下代码可靠地重现您的问题:

public class Main
{
  public static StringBuilder intToString(byte[] bs) {
    final StringBuilder sb = new StringBuilder();
    boolean started = false;
    for (Byte byt : bs) {
      if (started) sb.append(".");
      sb.append(String.valueOf(byt & 0xFF));
      started = true;
    }
    return sb;
  }

  public static void main(String[] args) {
    final byte[] bs = {-2, -1, 0, 1, 2};
    while (true) intToString(bs);
  }
}
这个问题几乎可以肯定地追溯到JIT编译器的错误。您观察到,一旦它第一次发生,它就会在每次后续调用中可靠地发生,这清楚地指向一个JIT编译事件,该事件将错误代码引入代码路径


如果对您可用,您可以激活诊断JVM选项,该选项将打印所有编译事件(
-XX:printcomilation
)。然后,您可以将这样的事件与异常开始出现的时刻关联起来。

我将代码片段留在这里,因为它仍然应该比原始代码运行得更快—以内存为代价—但请注意,实际上并不能解决问题。

private static final String[] STRING_CACHE = new String[256];

static {
  for(int i = 0; i <= 255; i++) {
    STRING_CACHE[i] = String.valueOf(i);
  }
}

public static String ipToString(ByteString bs) {
  if (bs == null || bs.isEmpty()) {
    return null;
  } else {
    StringBuilder sb = new StringBuilder();
    boolean started = false;
    for (Byte byt : bs) {
      if (started) {
        sb.append(".");
      }
      sb.append(STRING_CACHE[byt & 0xFF]);
      started = true;
    }

    return sb.toString();
  }
}
private static final String[]String_CACHE=新字符串[256];
静止的{

对于(int i=0;i这是一个JIT编译器错误,它是作为另一个修复程序的副作用引入JDK 8u20的:

该问题与自动装箱消除优化有关。
解决方法是通过
-XX:-EliminateAutoBox
JVM标志关闭优化

在最新的JDK 9源代码库中似乎也存在此问题。

我已经提交了错误报告:包含100%可复制的最小测试用例。

这是否属于多线程环境之外的情况?堆栈跟踪表明您正在将其作为线程池的一部分运行。是否存在同步问题?您使用的是什么jdk?如果您使用的是IBM JVM,JIT组件中似乎存在错误iler..它似乎比其他任何东西都更符合JITC错误。您最近的更新很重要:它清楚地指出了JIT编译器问题(内联或甚至可能是某些汇编宏代码)。当然这还不够,OP@KumarAbhinav也没有要求解决方法。帮助中心:“具体来说,这个问题要求什么?确保你的答案提供了这一点——或者是一个可行的替代方案“需要注意的是,这个错误在别处被描述为一年前已经修复。OP需要更新他的JVM版本。@HotLicks,但OP显然使用了最新的JVM?不过,链接到这个错误将是最接近这个问题的真实答案!@MarkoTopolnik-嗯,我猜是修复版本(对于一个几乎相同的错误)是在IBM JVM中,而这显然是Oracle版本,所以可能不一样。(或者可能是相同的,但Oracle尚未修复。)如果问题是由
for(Byte b:bs)
而不是
for(Byte b:bs)引起的
-请参阅我答案中的注释-您是否可以查看该更改是否可以重现问题?请参阅我的更新:该更改使其易于重现。从您的代码中不明显的一点是,
bs
是否返回了一个
字节
或一个
字节
,这是一个关键区别。一个补丁已被接受d.解决问题
public class Main
{
  public static StringBuilder intToString(byte[] bs) {
    final StringBuilder sb = new StringBuilder();
    boolean started = false;
    for (Byte byt : bs) {
      if (started) sb.append(".");
      sb.append(String.valueOf(byt & 0xFF));
      started = true;
    }
    return sb;
  }

  public static void main(String[] args) {
    final byte[] bs = {-2, -1, 0, 1, 2};
    while (true) intToString(bs);
  }
}
private static final String[] STRING_CACHE = new String[256];

static {
  for(int i = 0; i <= 255; i++) {
    STRING_CACHE[i] = String.valueOf(i);
  }
}

public static String ipToString(ByteString bs) {
  if (bs == null || bs.isEmpty()) {
    return null;
  } else {
    StringBuilder sb = new StringBuilder();
    boolean started = false;
    for (Byte byt : bs) {
      if (started) {
        sb.append(".");
      }
      sb.append(STRING_CACHE[byt & 0xFF]);
      started = true;
    }

    return sb.toString();
  }
}