[翻译] 死法无法预测

楼主: PsMonkey (痞子军团团长)   2014-04-25 18:11:10
※ [本文转录自 Translate-CS 看板 #1JMZIjTY ]
作者: PsMonkey (痞子军团团长) 看板: Translate-CS
标题: [翻译] 死法无法预测
时间: Fri Apr 25 18:10:49 2014
Blog 版:http://blog.dontcareabout.us/2014/04/blog-post.html
原文网址:https://plumbr.eu/blog/you-cannot-predict-the-way-you-die
BBS 版以 markdown 语法撰写
______________________________________________________________________
在花了一天对付另一个 [Heisenbug]:每当我快抓到原因,它就会变了样;
我想我在这个 case 中学到的东西应该有分享的价值。
[Heisenbug]: http://en.wikipedia.org/wiki/Heisenbug
我写了一个简单的范例来展示这个状况。在这个例子中,
我建立一个 `Map` 然后用无穷循环往里头狂塞 key-value:
class Wrapper {
public static void main(String args[]) throws Exception {
Map map = System.getProperties();
Random r = new Random();
while (true) {
map.put(r.nextInt(), "value");
}
}
}
你可能也看得出来,compile 然后执行这段程式码是不会有什么好下场。
正确来说,当用下面的指令执行时:
java -Xmx100m -XX:+UseParallelGC Wrapper
shell 就会出现 `java.lang.OutOfMemoryError: GC overhead limit exceeded`。
但如果用不同的 heap 大小、或是不同 GC,
我的 Mac OS X 10.9.2 + Oracle Hotspot JDK 1.7.0_45 会选择不同的死法。
例如设定比较小的 heap 来执行,如下:
java -Xmx10m -XX:+UseParallelGC Wrapper
application 会用比较熟悉的死法,
也就是在 `Map` 调整大小时炸 `java -Xmx100m -XX:+UseParallelGC Wrapper`。
用 ParallelGC 以外的 GC 算法,
像是 `-XX:+UseConcMarkSweepGC`、`-XX:+UseG1GC`,
炸出来的错误讯息是默认的 exception handler 抓到的,
因为 heap 已经耗尽,所以在 `Exception` 建立时甚至无法设定 stacktrace、
也就不会有 stacktrace:
My Precious:examples vladimir$ java -Xmx100m
-XX:+UseConcMarkSweepGC Wrapper
Exception: java.lang.OutOfMemoryError thrown from the
UncaughtExceptionHandler in thread "main"
这个故事的教训是:你无法选择你的 application 在资源不足的时候
会以哪一种方法挂掉,所以也无法用一系列特定的行为来推测。
在上头的例子就可以看到有三种完全不同的失败方式:
1. GC 内建的安全检查失败:
当 GC 花超过 98% 的时间在 GC 上但是没啥效果(heap 清出的空间少于 2%),
JVM 会放弃然后炸 `java.lang.OutOfMemoryError: GC overhead limit exceeded`。
2. 下一个操作无法取得更多内存:
每当下一个指令尝试要求比现在 heap 可用空间还大的内存,
就会炸 `java.lang.OutOfMemoryError: Java heap space`。
3. 你可能已经制造过这个状况,
当内存用完、JVM 无法建立一个新的 `OutOfMemoryError` instance、
也无法填 stacktrace 内容并把它送到 print stream 输出。
如此一来错误会是 [UncaughtExceptionHaneler] 炸出来的,
而且不走正规的控制流程。
这个 handler 人如其名,
在 thread 因为 uncaught exception 而终止时会发挥作用。
在这类案例中,JVM 会用它的 `UncaughtExceptionHandler` 查询 thread、
然后呼叫 handler 的 `uncaughtException()`。
所以每当你觉得抓到表示缺乏资源的错误时,再想一下。
系统可能处在一个脆弱的状态,你觉得你可以倚赖的征状会改变或是消失。
然后过了 12 个小时,只会让你跟我一样眼花撩乱不知所措。
[UncaughtExceptionHaneler]: http://docs.oracle.com/javase/7/docs/api/
java/lang/Thread.UncaughtExceptionHandler.html

Links booklink

Contact Us: admin [ a t ] ucptt.com