一、前言
最近一直在研究Java8 的動态編譯, 并且也被ZipFileIndex$Entry 記憶體洩漏所困擾,在無意中,看到一個第三方插件的動态編譯。并且編譯速度是原來的2-3倍。原本打算直接用這個插件,但是發現插件的編譯源碼存在我之前已經解決過的記憶體洩漏問題。是以拿其源碼,進行改善。
二、第三方插件
1、maven配置
我找到的這個第三方編譯插件有兩個,第一個是:Talismane Utilities ,在maven倉庫中可搜到相關pom的配置:
http://mvnrepository.com/search?q=Talismane+Utilities
這個插件也能編譯,但是編譯速度和記憶體洩漏問題依然存在(廢棄)
第二個插件是Java Runtime Compiler , 可在Maven倉庫中找到 : http://mvnrepository.com/artifact/net.openhft/compiler
我使用的版本是最新的2.3.1 , 進行反編譯後:
2、插件源碼更改
拿到Java Runtime Compiler插件的源碼後,能找到有個CachedCompiler類,我對其compilerFromJava方法進行了更改,加上了編譯options參數。具體代碼如下:
- Map<String, byte[]> compileFromJava(@NotNull String className, @NotNull String javaCode, @NotNull final PrintWriter writer, MyJavaFileManager fileManager) {
- Object compilationUnits;
- if(this.sourceDir != null) {
- String filename = className.replaceAll("\\.", '\\' + File.separator) + ".java";
- File file = new File(this.sourceDir, filename);
- CompilerUtils.writeText(file, javaCode);
- compilationUnits = CompilerUtils.s_standardJavaFileManager.getJavaFileObjects(new File[]{file});
- } else {
- this.javaFileObjects.put(className, new JavaSourceFromString(className, javaCode));
- compilationUnits = this.javaFileObjects.values();
- }
- System.setProperty("useJavaUtilZip", "true");
- 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");
- boolean ok = CompilerUtils.s_compiler.getTask(writer, fileManager, new DiagnosticListener<JavaFileObject>() {
- public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
- if(diagnostic.getKind() == Kind.ERROR) {
- writer.println(diagnostic);
- }
- }
- }, options, (Iterable)null, (Iterable)compilationUnits).call().booleanValue();
- Map<String, byte[]> result = fileManager.getAllBuffers();
- if(!ok) {
- if(this.sourceDir == null) {
- this.javaFileObjects.remove(className);
- }
- return Collections.emptyMap();
- } else {
- return result;
- }
- }
3、具體編譯時測試類
利用原來的測試類,以10萬個編譯測試為例,進行測試,編譯速度提升N倍,同時記憶體溢出問題也僅存在ZipFIleIndex
- package com.yunerp.web.util.run.compile;
- import com.yunerp.web.util.run.WebInterface;
- import com.yunerp.web.util.run.dynamic.compiler.CompilerUtils;
- import java.util.HashMap;
- import java.util.Map;
- public class DynaCompTest{
- public static Map<String,Object> map = new HashMap<>();
- public static void main(String[] args) throws Exception {
- String code = "import java.util.HashMap;\n" +
- "import com.yunerp.web.vaadin.message.alert;\n" +
- "import java.util.List;\n" +
- "import java.util.ArrayList;\n" +
- "import com.yunerp.web.vaadin.util.modularfuntion.base.BaseUtil;\n" +
- "import com.yunerp.web.vaadin.util.function.TableFuntionUtil;\n" +
- "import com.yunerp.web.vaadin.util.modularfuntion.stoUtil.StoUtil;\n" +
- "import java.util.Map;import com.yunerp.web.vaadin.util.modularfuntion.user.mini.HomePageUtil;\n" +
- "import com.yunerp.web.util.run.WebInterface;\n" +
- "\n" +
- "public class web2905763164651825363 implements WebInterface {\n" +
- " public Object execute(Map<String,Object> param) {\n" +
- " System.out.println(param.get(\"key\")+ \"次測試編譯\");" +
- " return null;\n" +
- " }\n" +
- "}";
- String name = "web2905763164651825363";
- for(int i=0;i<100000;i++){
- long time1 = System.currentTimeMillis();
- DynamicEngine de = new DynamicEngine();
- try {
- // Class cl = de.javaCodeToObject(name,code);
- Class cl = CompilerUtils.CACHED_COMPILER.loadFromJava(name, code);
- if (cl==null){
- System.out.println("編譯失敗/類加載失敗");
- continue;
- }
- WebInterface webInterface = (WebInterface)cl.newInstance();
- Map<String,Object> param = new HashMap<>();
- param.put("key",i);
- webInterface.execute(param);
- }catch (Exception e) {
- e.printStackTrace();
- }
- long time2 = System.currentTimeMillis();
- System.out.println("次數:"+i+" time:"+(time2-time1));
- }
- }
- }
4、編譯速度對比
之前的編譯代碼編譯速度:
使用更改後的第三方編譯代碼編譯速度如下:
注: 因為之前的就存在ZipFileIndex問題,更改後的編譯源碼也隻是提升編譯速度,ZipFileIndex記憶體洩漏的問題仍然存在,目前唯一的解決方案是更新Java8 到 Java10
原文位址:https://blog.csdn.net/moneyshi/article/details/82499058