日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自我修复的JVM

發布時間:2023/12/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自我修复的JVM 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這篇帖子是關于一個應用程序的示例,其中解決每個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()方法。

因此,讓我們從對源代碼的靜態分析開始,看看我們的期望是否正確:

  • 從第一次快速檢查起,該代碼確實無法完成,因為我們嘗試分配的內存超過了JVM可用的內存。
  • 如果我們仔細觀察,我們會注意到第一次分配發生在有作用域的塊中,這意味著在此塊中定義的變量僅對該塊可見。 這表明在完成塊后,這些字節應符合GC的條件。 因此,我們的代碼實際上應該從一開始就可以正常運行,因為當它嘗試分配更多 字節時 ,先前的分配字節應該已失效。
  • 如果現在查看編譯的類文件,將看到以下字節碼:
  • private static void allocateMemory(int);Code:0: getstatic #3 // Field SIZE:I3: newarray byte5: astore_1 6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;9: aload_1 10: arraylength 11: invokevirtual #5 // Method java/io/PrintStream.println:(I)V14: getstatic #3 // Field SIZE:I17: newarray byte19: astore_1 20: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;23: aload_1 24: arraylength 25: invokevirtual #5 // Method java/io/PrintStream.println:(I)V ---- cut for brevity ----

    在這里我們看到,在偏移量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

    總結

    以上是生活随笔為你收集整理的自我修复的JVM的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。