ʞɔı*_*ɔıu 28 java jvm jvm-hotspot java-8
为什么这段代码有时会产生ArrayOutOfBoundsException?怎么可能String.valueOf(int)
呢?
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.valueOf(byt & 0xFF));
started = true;
}
return sb.toString();
}
}
java.lang.ArrayIndexOutOfBoundsException: -81914
at java.lang.Integer.getChars(Integer.java:458)
at java.lang.Integer.toString(Integer.java:402)
at java.lang.String.valueOf(String.java:3086)
at com.mystuff.mypackage.ipToString(MyCode.java:1325)
...
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Run Code Online (Sandbox Code Playgroud)
更新
当发生这种情况时,我不知道字节的值,但似乎不应该有任何可能的字节值.
一旦发生一次,每次调用都会以相同的异常出错.
环境:
Run Code Online (Sandbox Code Playgroud)java version "1.8.0_20" Java(TM) SE Runtime Environment (build 1.8.0_20-b26) Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
apa*_*gin 18
这是JDK 8u20中引入的JIT编译器错误,作为另一个修复的副作用:
JDK-8042786
该问题与自动装箱消除优化有关.
解决方法是通过-XX:-EliminateAutoBox
JVM标志关闭优化
看起来这个问题也存在于最新的JDK 9源代码库中.
我已经提交了错误报告:https://bugs.openjdk.java.net/browse/JDK-8058847,包含100%可重现的最小测试用例.
我可以使用以下代码可靠地重现您的问题:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
该问题几乎肯定会被追溯到JIT编译器错误.您的观察一旦它第一次发生,它会在每次后续调用中可靠地发生,干净地指向JIT编译事件,该事件将错误代码引入代码路径.
如果您可以使用它,则可以激活诊断JVM选项,该选项将打印所有编译事件(-XX:PrintCompilation
).然后,您可以将此类事件与异常开始出现的时刻相关联.
我在这里留下代码片段,因为它仍然应该比原始代码运行得更快 - 以内存为代价 - 但是请注意它实际上并没有解决问题.
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();
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
852 次 |
最近记录: |