Java動態編譯優化——ZipFileIndex記憶體洩漏問題分析解決
一、前言:
前幾天解決了URLClassLoader記憶體洩漏的問題,但是解決問題就像剝洋蔥,剝去了外層,內層 問題又暴露出來了。當URLClassLoader記憶體洩漏解決, 需要解決的就是ZipFileIndex記憶體洩漏的問題了,而且這個問題折騰了我2天半的時間。
URLClassLoader問題解決:https://blog.csdn.net/moneyshi/article/details/81939477
二、ZipFileIndex問題發現
在執行動態編譯的時候,用VisualVM分析堆Dump,發現com.sun.tools.javac.file.ZipFileIndex$Entry
查詢資料,ZipFileIndex 是JavacFileManager裡面用到的一個處理檔案的類,在jdk1.7之後加入進來的,jdk1.9裡面被刪除了。
三、解決方案
1、設定useJavaUtilZip
為了解決ZipFileIndex記憶體洩漏的問題,查閱大量資料,其中有個解決方案就是編譯時設定useJavaUtilZip=true,具體程式碼如下:
System.setProperty("useJavaUtilZip", "true"); //使用編譯選項可以改變預設編譯行為。編譯選項是一個元素為String型別的Iterable集合 List<String> options = new ArrayList<>(); options.add("-encoding"); options.add("UTF-8"); options.add("-classpath"); // //獲取系統構建路徑 options.add(buildClassPath()); //不使用SharedNameTable (jdk1.7自帶的軟引用,會影響GC的回收,jdk1.9已經解決) options.add("-XDuseUnsharedTable"); options.add("-XDuseJavaUtilZip"); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, options, null, jfiles);
但是實際上並沒什麼效果。ZipFileIndex記憶體佔比依然很高(不知道我是哪設定有問題)
2、升級JDK版本,由Java8升級到Java9
花了兩天時間,都沒找到什麼好的解決方案,於是我想到去Oracle/Java 的Bug列表去找我想要的答案,終於讓我找到了資料,說明了JDK升級到9之後,會刪除ZipFileIndex相關的類,加入java.nio.file來處理檔案編譯,具體如下:
Oracle/Java的bug列表:
參考文獻:
https://bugs.java.com/view_bug.do?bug_id=8039262
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8061702
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8059976
升級Java 9 版本後,動態編譯 ZipFileIndex不在出現。 問題完美解決。
後續可能更新String 、 LinkedList 、 HashMap的記憶體洩漏問題解決方案。