一、前言

最近一直在研究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参数。具体代码如下:

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
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

text
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
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/shijing266/article/details/82499058?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168474994416800226590860%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=168474994416800226590860&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-28-82499058-null-null.142^v87^control_2,239^v2^insert_chatgpt&utm_term=java%E4%BC%98%E5%8C%96