• Java动态编译优化——提升编译速度(N倍)


    一、前言

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

    1. Map<String, byte[]> compileFromJava(@NotNull String className, @NotNull String javaCode, @NotNull final PrintWriter writer, MyJavaFileManager fileManager) {
    2. Object compilationUnits;
    3. if(this.sourceDir != null) {
    4. String filename = className.replaceAll("\.", '\' + File.separator) + ".java";
    5. File file = new File(this.sourceDir, filename);
    6. CompilerUtils.writeText(file, javaCode);
    7. compilationUnits = CompilerUtils.s_standardJavaFileManager.getJavaFileObjects(new File[]{file});
    8. } else {
    9. this.javaFileObjects.put(className, new JavaSourceFromString(className, javaCode));
    10. compilationUnits = this.javaFileObjects.values();
    11. }
    12. System.setProperty("useJavaUtilZip", "true");
    13. List<String> options = new ArrayList<>();
    14. options.add("-encoding");
    15. options.add("UTF-8");
    16. options.add("-classpath");
    17. //获取系统构建路径
    18. options.add(buildClassPath());
    19. //不使用SharedNameTable (jdk1.7自带的软引用,会影响GC的回收,jdk1.9已经解决)
    20. options.add("-XDuseUnsharedTable");
    21. options.add("-XDuseJavaUtilZip");
    22. boolean ok = CompilerUtils.s_compiler.getTask(writer, fileManager, new DiagnosticListener<JavaFileObject>() {
    23. public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
    24. if(diagnostic.getKind() == Kind.ERROR) {
    25. writer.println(diagnostic);
    26. }
    27. }
    28. }, options, (Iterable)null, (Iterable)compilationUnits).call().booleanValue();
    29. Map<String, byte[]> result = fileManager.getAllBuffers();
    30. if(!ok) {
    31. if(this.sourceDir == null) {
    32. this.javaFileObjects.remove(className);
    33. }
    34. return Collections.emptyMap();
    35. } else {
    36. return result;
    37. }
    38. }

    3、具体编译时测试类

    利用原来的测试类,以10万个编译测试为例,进行测试,编译速度提升N倍,同时内存溢出问题也仅存在ZipFIleIndex

    1. package com.yunerp.web.util.run.compile;
    2. import com.yunerp.web.util.run.WebInterface;
    3. import com.yunerp.web.util.run.dynamic.compiler.CompilerUtils;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6. public class DynaCompTest{
    7. public static Map<String,Object> map = new HashMap<>();
    8. public static void main(String[] args) throws Exception {
    9. String code = "import java.util.HashMap; " +
    10. "import com.yunerp.web.vaadin.message.alert; " +
    11. "import java.util.List; " +
    12. "import java.util.ArrayList; " +
    13. "import com.yunerp.web.vaadin.util.modularfuntion.base.BaseUtil; " +
    14. "import com.yunerp.web.vaadin.util.function.TableFuntionUtil; " +
    15. "import com.yunerp.web.vaadin.util.modularfuntion.stoUtil.StoUtil; " +
    16. "import java.util.Map;import com.yunerp.web.vaadin.util.modularfuntion.user.mini.HomePageUtil; " +
    17. "import com.yunerp.web.util.run.WebInterface; " +
    18. " " +
    19. "public class web2905763164651825363 implements WebInterface { " +
    20. " public Object execute(Map<String,Object> param) { " +
    21. " System.out.println(param.get("key")+ "次测试编译");" +
    22. " return null; " +
    23. " } " +
    24. "}";
    25. String name = "web2905763164651825363";
    26. for(int i=0;i<100000;i++){
    27. long time1 = System.currentTimeMillis();
    28. DynamicEngine de = new DynamicEngine();
    29. try {
    30. // Class cl = de.javaCodeToObject(name,code);
    31. Class cl = CompilerUtils.CACHED_COMPILER.loadFromJava(name, code);
    32. if (cl==null){
    33. System.out.println("编译失败/类加载失败");
    34. continue;
    35. }
    36. WebInterface webInterface = (WebInterface)cl.newInstance();
    37. Map<String,Object> param = new HashMap<>();
    38. param.put("key",i);
    39. webInterface.execute(param);
    40. }catch (Exception e) {
    41. e.printStackTrace();
    42. }
    43. long time2 = System.currentTimeMillis();
    44. System.out.println("次数:"+i+" time:"+(time2-time1));
    45. }
    46. }
    47. }

    4、编译速度对比

    之前的编译代码编译速度:

    使用更改后的第三方编译代码编译速度如下:

    注: 因为之前的就存在ZipFileIndex问题,更改后的编译源码也只是提升编译速度,ZipFileIndex内存泄漏的问题仍然存在,目前唯一的解决方案是升级Java8 到 Java10

    原文地址:https://blog.csdn.net/moneyshi/article/details/82499058
  • 相关阅读:
    linux学习之线程篇(二)
    linux学习之线程篇(一)
    linux学习之进程篇(四)
    linux学习之信号篇(二)
    linux学习之信号篇(一)
    myshell案例
    linux学习之gdb调试工具篇
    linux学习之Makefile篇
    linux学习之进程篇(三)
    Linux常用命令-1
  • 原文地址:https://www.cnblogs.com/jpfss/p/10978351.html
Copyright © 2020-2023  润新知