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;\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

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM