前几天解决了URLClassLoader内存泄漏的问题,但是解决问题就像剥洋葱,剥去了外层,内层 问题又暴露出来了。当URLClassLoader内存泄漏解决, 需要解决的就是ZipFileIndex内存泄漏的问题了,而且这个问题折腾了我2天半的时间。
URLClassLoader问题解决:https://blog.csdn.net/moneyshi/article/details/81939477
在执行动态编译的时候,用VisualVM分析堆Dump,发现com.sun.tools.javac.file.ZipFileIndex$Entry 类和实例内存占比特别高,仅居String之后,具体如下图:
查询资料,ZipFileIndex 是JavacFileManager里面用到的一个处理文件的类,在jdk1.7之后加入进来的,jdk1.9里面被删除了。
为了解决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内存占比依然很高(不知道我是哪设置有问题)
花了两天时间,都没找到什么好的解决方案,于是我想到去Oracle/Java 的Bug列表去找我想要的答案,终于让我找到了资料,说明了JDK升级到9之后,会删除ZipFileIndex相关的类,加入java.nio.file来处理文件编译,具体如下:
Oracle/Java的bug列表:
https://www.oracle.com/search/results?Ntt=&Dy=1&Nty=1&cat=bugs&Ntk=S3
参考文献:
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的内存泄漏问题解决方案。