一、前言
最近一直在研究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