问题描述
在详细模式下运行编译器,JDK8编译器停止在一个大型项目上,因此在JDK8上,大生成转换器类(映射),用于从服务器到客户端的实体。
在几种情况下,转换器方法从同一个Mapping类中调用其他转换器方法。
由于解决方法尝试将Mapping文件拆分为多个文件。当仅编译Mapping类或其包含项目(projectA)时,这显着提高了性能。但是编译时间对于从projectA调用转换器方法的其他项目是非常慢的。
另一个解决方法是使所有的转换方法返回null,不调用任何其他。
ProjectA使用泛型,但由于它与JDK6兼容,而JDK6没有引入泛化类型推断,也许是另一个导致这种减速的JDK8错误。
因此可能在上下文之外,但对于广义类型推理,下面的线程建议升级到JDK9。但由于它还没有发布,它不是一个可行的选择,升级。
如果修复的后端将对JDK8完成,这将是理想的。这是在以下StackOverflow线程中请求的,但是还没有来自Oracle团队的回复。
JDK8堆:
您已经注意到,,当涉及基于通用目标打字的重载解决方案。在你的情况下的原因之一可能是编译器需要从一个赋值类型中找到适当的方法。
ResultVO<东西,东西> result = Mapping.convert(...);
// heavy lookup here --------------------------- ^^^^^^^
如果你在控制代码生成器,并且不受向后兼容性约束,那么可能值得考虑避免重载 convert()
方法。没有重载,编译器不必做重载分解工作,既不在你的映射代码内,也不在调用站点。这将肯定会快得多。
尝试1:在方法名称中使用参数类型:
class Mapping {
public static ResponseItemVO convertResponseItem(ResponseItem pArg0){
if(pArg0 == null){
return null;
}
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(pArg0.getErrorDetails());
ret.setResult(Mapping.convertResult(pArg0.getResult()));
ret.setIdentifier(Mapping.convertIdentifier(pArg0.getIdentifier()));
return ret;尝试2:通过将转换方法移动到其他地方,例如,将转换方法移动到其它地方。到 VO
类型
class ResponseItemVO {
public static ResponseItemVO from(ResponseItem pArg0){
if(pArg0 == null){
return null;
}
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(pArg0.getErrorDetails());
ret.setResult(ResultVO.from(pArg0.getResult()));
ret.setIdentifier(IdentifierVO.from(pArg0.getIdentifier()));
return ret;
}
}
或更好...
class ResponseItem {
public ResponseItemVO toVO(){
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(getErrorDetails());
ret.setResult(getResult()。toVO());
ret.setIdentifier(getIdentifier()。toVO());
return ret;
}
}
Trying to upgrade to JDK8 on a big project, compilation goes really slow on JDK8 compared to JDK7.
Running the compiler in verbose mode, JDK8 compiler stops at a big generated converter class(Mapping) for entities from server to client.The converter methods in several cases call other converter methods from the same Mapping class.
As a workaround tried to split the Mapping file into multiple files. This visibly improved performance when only compiling the Mapping class or it's containing project(projectA). But compile time was very slow for other projects which invoke converter methods from projectA.
Another workaround was to make all convert methods return null, not calling anything else. Again, the performance was good for projectA but not for depending projects.
ProjectA uses generics but since it is compatible with JDK6, which didn't have generalized type inference introduced, maybe it's another JDK8 bug that causes this slowdown.
So possibly out of context but for generalized type inference, some threads like below suggest an upgrade to JDK9. But since it's not yet released, it's not a viable option as upgrade.It'd be ideal if a backport of the fix would be done to JDK8. This was requested in the following StackOverflow thread but no reply from Oracle team yet.
Slow compilation with jOOQ 3.6+, plain SQL, and the javac compiler
I've attached 2 screenshots of how the heap looks in JDK7 vs JDK8. Could this be a cause for the JDK8 slowdown?
Thank you!
Update 20160314
The converter methods from Mapping class look like:
public static ResponseItemVO convert (ResponseItem pArg0){
if(pArg0==null){
return null;
}
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(pArg0.getErrorDetails());
ret.setResult(Mapping.convert(pArg0.getResult()));
ret.setIdentifier(Mapping.convert(pArg0.getIdentifier()));
return ret;
}
And the VO looks like:
public class ResponseItemVO extends ResultVO<IdentifierVO, DetailsVO > {
public ResponseItemVO() {}
}
JDK7 Heap:JDK8 Heap:
解决方案 You've noticed already, there's a severe performance regression in Java 8 when it comes to overload resolution based on generic target typing. One of the reasons in your case might be the fact that the compiler needs to find the appropriate method from an assignment type
ResultVO<Something, Something> result = Mapping.convert(...);
// heavy lookup here ---------------------------^^^^^^^
If you're in control of the code generator, and not constrained by backwards compatibility, it might be worth thinking about avoiding the overloading of the convert()
method. Without overloading, the compiler doesn't have to do the overload resolution work, neither inside of your mapping code, nor at the call site. This will certainly be much much faster.
Attempt 1: By using the parameter type in the method name:
class Mapping {
public static ResponseItemVO convertResponseItem(ResponseItem pArg0){
if (pArg0==null){
return null;
}
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(pArg0.getErrorDetails());
ret.setResult(Mapping.convertResult(pArg0.getResult()));
ret.setIdentifier(Mapping.convertIdentifier(pArg0.getIdentifier()));
return ret;
}
}
Attempt 2: By moving the convert method elsewhere, e.g. into the VO
type
class ResponseItemVO {
public static ResponseItemVO from(ResponseItem pArg0){
if (pArg0==null){
return null;
}
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(pArg0.getErrorDetails());
ret.setResult(ResultVO.from(pArg0.getResult()));
ret.setIdentifier(IdentifierVO.from(pArg0.getIdentifier()));
return ret;
}
}
Or better...
class ResponseItem {
public ResponseItemVO toVO(){
ResponseItemVO ret = new ResponseItemVO();
ret.setErrorDetails(getErrorDetails());
ret.setResult(getResult().toVO());
ret.setIdentifier(getIdentifier().toVO());
return ret;
}
}
这篇关于缓慢的JDK8编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!