Considering the code:
someList.forEach(x -> System.out.format("element %s", x));
Theoretically, it should be possible to inline this code and eliminate the indirect function calls by first inlining the forEach
method, and then inlining the lambda function body in the inlined forEach
code.
Is HotSpot capable of performing this optimization? What restrictions govern whether or not it is performed in a particular situation?
Your lambda expression is compiled into an ordinary method, while the JRE will generate a class fulfilling the functional interface and calling that method. In current HotSpot versions, this generated class works almost like an ordinary class, the main differences are that it may invoke private
target methods and that it is not back-referenced by a ClassLoader
.
None of these properties hinders optimizations, in the end, you only have a chain of ordinary method invocations. The biggest obstacle with such code with the current JVMs are inlining limits, regarding the maximum depth (defaults to nine nested methods IIRC) and maximum resulting code size. Some of these defaults are very old and were not revised since their last definition. However, such limits may affect very long stream pipelines, not a use case like your plain forEach
.
So the general answer is that HotSpot is capable of performing such optimizations, but like with all optimizations, it will let your code run a few times, before determining whether it is performance critical and perform the optimization(s), if so.
That is actually really easy to prove. Here is some very simple code:
for (int i = 0; i < 100_000; ++i) {
Stream.of(1, 2, 3, 4)
.map(x -> x * 2)
.collect(Collectors.toList());
}
When I compile this I can see that the generated de-sugared method (via javap
) for the lambda expression is called : lambda$main$0
(in jdk-9, but this does not matter much).
And then I can simply run this code with:
java -XX:-TieredCompilation
-XX:CICompilerCount=1
-XX:+UnlockDiagnosticVMOptions
-XX:+PrintCompilation
-XX:+PrintInlining
-XX:CompileCommand="print, *.lambda"
InlineLambdaTest
> inline.txt
And looking at the file there are lines like this:
Inline::lambda$main$0 (10 bytes) inline (hot)
So inlining for such a method works the usual way. Notice that the will be many more lines that start with ...lambda...
as there are many other places internally that use lambda expression that are considered hot too.
来源:https://stackoverflow.com/questions/44161545/can-hotspot-inline-lambda-function-calls