2017-05-24 36 views
5

Biorąc pod uwagę kod:Czy funkcja Hotline wbudowanych wywołań funkcji lambda?

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

Teoretycznie powinno być możliwe do inline ten kod i wyeliminować pośrednie wywołania funkcji przez pierwszy inline metody forEach, a następnie inline ciało funkcji lambda w inlined kodu forEach.

Czy HotSpot jest w stanie przeprowadzić tę optymalizację? Jakie ograniczenia określają, czy jest ono wykonywane w konkretnej sytuacji?

Odpowiedz

4

Twoje wyrażenie lambda jest kompilowane w zwykły sposób, podczas gdy środowisko JRE generuje klasę spełniającą interfejs funkcjonalny i wywołującą tę metodę. W aktualnych wersjach HotSpot ta wygenerowana klasa działa prawie jak zwykła klasa, główne różnice polegają na tym, że może ona wywoływać metody docelowe private i że nie jest ona przywoływana wstecz przez ClassLoader.

Żadna z tych właściwości nie utrudnia optymalizacji, w końcu masz tylko łańcuch zwykłych wywołań metod. Największą przeszkodą z takim kodem z bieżącymi maszynami JVM są limity wstawiania, dotyczące maksymalnej głębokości (domyślnie dziewięciu metod zagnieżdżonych IIRC) i maksymalnego wynikowego rozmiaru kodu. Niektóre z tych wartości domyślnych są bardzo stare i nie zostały zmienione od czasu ostatniej definicji. Jednak takie ograniczenia mogą dotyczyć bardzo długich potoków strumieniowych, a nie przypadek użycia, taki jak zwykły forEach.

Tak więc ogólna odpowiedź jest taka, że ​​HotSpot jest w stanie przeprowadzić takie optymalizacje, ale podobnie jak przy wszystkich optymalizacjach, pozwoli na uruchomienie kodu kilka razy, przed określeniem, czy jest on krytyczny i wykonuje optymalizację, więc.

+0

Zobacz także [Jak będą kompilowane funkcje Java lambda?] (Https://stackoverflow.com/q/16827262/2711488) – Holger

+2

pamiętasz poprawnie: 'intx MaxInlineLevel = 9'. – Eugene

3

To naprawdę jest naprawdę łatwe do udowodnienia. Oto bardzo prosty kod:

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

Kiedy mogę skompilować to widzę, że wygenerowany odcukrzanych sposób (poprzez javap) dla wyrażenia lambda nazywa się: lambda$main$0 (w JDK-9, ale tego nie robi dużo materii).

A potem mogę po prostu uruchomić ten kod z:

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

i patrząc na pliku są linie takie jak to:

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

Więc inline dla takiego metoda działa w zwykły sposób. Zauważ, że będzie o wiele więcej linii zaczynających się od ...lambda..., ponieważ istnieje wiele innych miejsc wewnątrz, które używają wyrażenia lambda, które są uważane za gorące.

Powiązane problemy