一、前言

最近一直在研究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;\n" +
  10. "import com.yunerp.web.vaadin.message.alert;\n" +
  11. "import java.util.List;\n" +
  12. "import java.util.ArrayList;\n" +
  13. "import com.yunerp.web.vaadin.util.modularfuntion.base.BaseUtil;\n" +
  14. "import com.yunerp.web.vaadin.util.function.TableFuntionUtil;\n" +
  15. "import com.yunerp.web.vaadin.util.modularfuntion.stoUtil.StoUtil;\n" +
  16. "import java.util.Map;import com.yunerp.web.vaadin.util.modularfuntion.user.mini.HomePageUtil;\n" +
  17. "import com.yunerp.web.util.run.WebInterface;\n" +
  18. "\n" +
  19. "public class web2905763164651825363 implements WebInterface {\n" +
  20. " public Object execute(Map<String,Object> param) {\n" +
  21. " System.out.println(param.get(\"key\")+ \"次测试编译\");" +
  22. " return null;\n" +
  23. " }\n" +
  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

Java动态编译优化——提升编译速度(N倍)的更多相关文章

  1. COCOS2DX 3.0 优化提升渲染速度 Auto-batching

    COCOS2DX 3.0 优化提升渲染速度 Auto-batching 近期在看COCOS2DX 3.0的Auto-batching合批与Auto Culling动态缩减功能以下就来细致看看吧:整合好 ...

  2. vue-cli3使用 DllPlugin 实现预编译,提升构建速度

    在项目打包上有两个目标:减少打包代码体积和加快打包速度 1. 减少打包体积: (1)对于用的比较少的库,可以去掉(我去掉了jquery以及lodash),用到的地方,参考源码自己写 (2)非用不可的又 ...

  3. java 动态生成类再编译最后代理

    package spring.vhostall.com.proxy; public interface Store { public void sell(); } ------------------ ...

  4. js优化提升访问速度

    一.给JS文件减肥. 有的人为了给网站增加炫目效果,往往会使用一些JS效果代码,这在上个世纪似乎还很流行,对于现在来说,最好在用户体验确实需要的情况下,使用这些东西.至于希望给自己的JS文件减肥的童鞋 ...

  5. JVM性能优化系列-(6) 晚期编译优化

    6. 晚期编译优化 晚期编译优化主要是在运行时做的一些优化手段. 6.1 JIT编译器 在部分的商用虚拟机中,java程序最初是通过解释器(Interpreter) 进行解释执行的,当虚拟机发现某个方 ...

  6. JVM性能优化系列-(5) 早期编译优化

    5. 早期编译优化 早起编译优化主要指编译期进行的优化. java的编译期可能指的以下三种: 前端编译器:将.java文件变成.class文件,例如Sun的Javac.Eclipse JDT中的增量式 ...

  7. Java程序性能优化Tip

    本博客是阅读<java time and space performance tips>这本小书后整理的读书笔记性质博客,增加了几个测试代码,代码可以在此下载:java时空间性能优化测试代 ...

  8. 微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结

    1.引言 岁月真是个养猪场,这几年,人胖了,微信代码也翻了. 记得 14 年转岗来微信时,用自己笔记本编译微信工程才十来分钟.如今用公司配的 17 年款 27-inch iMac 编译要接近半小时:偶 ...

  9. JavaScript的工作原理:解析、抽象语法树(AST)+ 提升编译速度5个技巧

    这是专门探索 JavaScript 及其所构建的组件的系列文章的第 14 篇. 如果你错过了前面的章节,可以在这里找到它们: JavaScript 是如何工作的:引擎,运行时和调用堆栈的概述! Jav ...

随机推荐

  1. Leetcode733.Flood Fill图像渲染

    有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间. 给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newCol ...

  2. Hdu 4810

    2014-05-02 15:53:50 题目连接 2013年南京现场赛的题目,现场的时候,排在我们前面的队伍基本都过了这题,我们后面的队伍也有不少过了这题,唯独我们没有.. 后来是Qingyu Sha ...

  3. C++复制初始化的限制

    相比于直接初始化,复制初始化有更加严格的限制. 1:在复制初始化时,不能使用声明为explicit的构造函数进行的隐式转换.而直接初始化则是允许的: struct Exp { explicit Exp ...

  4. MaxCompute如何对SQL查询结果实现分页获取

    由于MaxCompute SQL本身不提供类似数据库的select * from table limit x offset y的分页查询逻辑.但是有很多用户希望在一定场景下能够使用获取类似数据库分页的 ...

  5. php代码在模板页的活用

  6. php上传文件与图片到七牛的实例详解

    上传文件到七牛最简单的方式就是使用七牛官方最新的SDK 用composer安装PHP SDK composer require qiniu/php-sdk 上传文件到七牛 use Qiniu\Auth ...

  7. SGU 103 Traffic Lights【最短路】

    题目链接: http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=16530 题意: 给定每个点最初的颜色,最初颜色持续时间,以 ...

  8. redux之createStore方法底层封装模拟

    首先在看代码之前让我们一起回顾下redux的思想吧   首先redux就是一个MVC思想的框架,他总体是遵循数据的单向流动自顶向下流动 在我们仓库中有一个initState用来存储着我们的初始数据 另 ...

  9. 《C语言深度解剖》学习笔记之函数

    第6章 函数 1.编码风格 [规则6-1]每一个函数都必须有注释 [规则6-2]每个函数定义之后以及每个文件结束之后都要加若干个空行 [规则6-3]在一个函数体内,变量定义与函数语句之间要加空行 [规 ...

  10. @codeforces - 1096G@ Lucky Tickets

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 已知一个数(允许前导零)有 n 位(n 为偶数),并知道组成这个 ...