2017-05-24 5 views
5

コードを考慮:HotSpotインラインラムダ関数が呼び出すことはできますか?

someList.forEach(x -> System.out.format("element %s", x)); 

を理論的には、このコードをインライン第forEach方法をインライン化し、次いでインラインforEachコードにラムダ関数本体をインライン化することによって、間接的関数呼び出しを排除することが可能であるべきです。

この最適化を実行できるHotSpotはありますか?特定の状況で実行されるかどうかはどのような制限事項がありますか?

答えて

4

ラムダ式は通常の方法にコンパイルされますが、JREは機能インターフェイスを満たし、そのメソッドを呼び出すクラスを生成します。現在のHotSpotバージョンでは、この生成クラスは通常のクラスとほぼ同じように機能しますが、主な違いはターゲットメソッドを呼び出す可能性があり、ClassLoaderによって逆参照されないことです。

これらのプロパティはどれも最適化を妨げません。結局、通常のメソッド呼び出しの連鎖しかありません。現在のJVMでのこのようなコードの最大の障害は、最大深度(デフォルトで9つのネストされたメソッドIIRC)と最大の結果コードサイズに関するインライン化の制限です。これらのデフォルトのうちのいくつかは非常に古いものであり、最後の定義以来改訂されていません。ただし、このような制限は、非常に長いストリームパイプラインに影響する可能性があります。普通のforEachのようなユースケースではありません。

一般的な答えはHotSpotがこのような最適化を実行できることですが、すべての最適化と同様に、コードが数回実行され、パフォーマンスが重要かどうかを判断して最適化を実行しますそう。

+0

[Javaラムダ関数はどのようにコンパイルされるのですか?](https://stackoverflow.com/q/16827262/2711488) – Holger

+2

「intx MaxInlineLevel = 9'」を正確に思い出してください。 – Eugene

3

これは実際に証明するのが実際に簡単です。私はこれをコンパイルすると

for (int i = 0; i < 100_000; ++i) { 
     Stream.of(1, 2, 3, 4) 
       .map(x -> x * 2) 
       .collect(Collectors.toList()); 
} 

私はラムダ式について(javapを経由して)生成された脱糖メソッドが呼び出されることを確認することができます:ここにいくつかの非常に簡単なコードであるlambda$main$0(JDK-9には、これはそうではありません多くのこと)。

そして、私は単純にこのコードを実行することができますので、このような方法のためにインライン化すると、通常のように動作します

Inline::lambda$main$0 (10 bytes) inline (hot) 

java -XX:-TieredCompilation 
     -XX:CICompilerCount=1 
     -XX:+UnlockDiagnosticVMOptions 
     -XX:+PrintCompilation 
     -XX:+PrintInlining 
     -XX:CompileCommand="print, *.lambda" 
     InlineLambdaTest 
     > inline.txt 

そして、このような行があるファイルを見ています。 ...lambda...で始まるより多くの行があることに注意してください。これは、ラムダ式を使用する他の多くの場所も暑いと考えられているからです。

関連する問題