jvm7 jvm8_自我修复的JVM
jvm7 jvm8
這篇帖子是關于一個應用程序的示例,其中解決每個IT問題的第一個解決方案-“您是否嘗試過將其關閉并重新打開”-可能適得其反,弊大于利。
我們不需要關閉電源,而是擁有可以自愈的應用程序:它在一開始就失敗了,但過了一段時間便開始平穩運行。 為了舉例說明這種應用的實際應用,我們以最簡單的方式重新創建了該應用, 并從Heinz Kabutz的Java Newsletter已有5年歷史的帖子中汲取了靈感 :
package eu.plumbr.test;public class HealMe {private static final int SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.6);public static void main(String[] args) throws Exception {for (int i = 0; i < 1000; i++) {allocateMemory(i);}}private static void allocateMemory(int i) {try {{byte[] bytes = new byte[SIZE];System.out.println(bytes.length);}byte[] moreBytes = new byte[SIZE];System.out.println(moreBytes.length);System.out.println("I allocated memory successfully " + i);} catch (OutOfMemoryError e) {System.out.println("I failed to allocate memory " + i);}} }上面的代碼在一個循環中分配兩個大塊內存。 這些分配中的每一個都等于總可用堆大小的60%。 由于分配是在同一方法中按順序進行的,因此人們可能希望此代碼不斷拋出java.lang.OutOfMemoryError:Java堆空間錯誤,并且永遠不會成功完成allocateMemory()方法。
因此,讓我們從對源代碼的靜態分析開始,看看我們的期望是否正確:
在這里我們看到,在偏移量3-5上,第一個數組被分配并存儲到索引為1的局部變量中。然后,在偏移量17上,另一個數組將被分配。 但是第一個數組仍由局部變量引用,因此第二個分配應始終因OOM而失敗。 字節碼解釋器只是不能讓GC清理第一個數組,因為它仍然被嚴格引用。
我們的靜態代碼分析向我們表明,由于兩個根本原因,所提供的代碼不應成功運行,而在一種情況下,應該可以成功運行。 這三者中哪一個是正確的? 讓我們實際運行它,自己看看。 事實證明,這兩個結論都是正確的。 首先,應用程序無法分配內存。 但是一段時間后(在具有Java 8的Mac OS X上,它發生在迭代#255上),分配開始成功:
java -Xmx2g eu.plumbr.test.HealMe 1145359564 I failed to allocate memory 0 1145359564 I failed to allocate memory 1… cut for brevity ...I failed to allocate memory 254 1145359564 I failed to allocate memory 255 1145359564 1145359564 I allocated memory successfully 256 1145359564 1145359564 I allocated memory successfully 257 1145359564 1145359564 Self-healing code is a reality! Skynet is near...為了理解實際發生的事情,我們需要思考一下,程序執行期間會發生什么變化? 當然,顯而易見的答案是可以進行即時編譯。 您還記得嗎,即時編譯是JVM的一種內置機制,可以優化代碼熱點。 為此,JIT監視正在運行的代碼,并且在檢測到熱點時,JIT會將您的字節碼編譯為本機代碼,在過程中執行不同的優化,例如方法內聯和消除無效代碼。
通過打開以下命令行選項并重新啟動程序,看看是否是這種情況:
-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:+LogCompilation這將生成一個日志文件,在本例中為hotspot_pid38139.log,其中38139是Java進程的PID。 在此文件中,可以找到以下行:
<task_queued compile_id='94' method='HealMe allocateMemory (I)V' bytes='83' count='256' iicount='256' level='3' stamp='112.305' comment='tiered' hot_count='256'/>這意味著,在執行256次allocateMemory()方法之后,C1編譯器決定將該方法排隊以進行C1層3編譯。 您可以在此處獲得有關分層編譯級別和不同閾值的更多信息。 因此,我們的前256次迭代是在解釋模式下運行的,在該模式下,字節碼解釋器作為一個簡單的堆棧機,無法事先知道是否會繼續使用某些變量(在這種情況下為字節)。 但是JIT可以立即看到整個方法,因此可以推斷出不再使用字節,并且實際上可以使用GC。 因此,垃圾收集最終可以發生,并且我們的程序神奇地自我修復了。 現在,我只希望沒有讀者真正負責在生產中調試這種情況。 但是,如果您希望使某人的生活陷入困境,那么將這樣的代碼引入生產環境將是實現此目標的肯定方法。
翻譯自: https://www.javacodegeeks.com/2014/12/self-healing-jvm.html
jvm7 jvm8
總結
以上是生活随笔為你收集整理的jvm7 jvm8_自我修复的JVM的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 占比怎么算计算公式 方法交给你
- 下一篇: 麻辣洗怎么用 麻辣洗使用方法