Czy w Javie są funkcje wbudowane?


112

Czy w javie istnieje koncepcja funkcji inline, czy też została ona zastąpiona czymś innym? Jeśli tak, jak jest używany? Słyszałem, że public, statici finalmetody są funkcje inline. Czy możemy stworzyć własną funkcję inline?


4
Dla wyjaśnienia, masz na myśli en.wikipedia.org/wiki/Inline_function , a nie en.wikipedia.org/wiki/Anonymous_function , prawda?
JW.

3
Drobny komentarz: przedwczesna optymalizacja jest źródłem wszelkiego zła. Bez pełnego zrozumienia natury publicznego, statycznego i ostatecznego, nie można naprawdę zrozumieć wpływu, jaki może mieć inlining - a to zależy od używanej maszyny JVM. Najpierw odpowiedz, dlaczego musisz coś wbudować: prawie pewne jest, że istnieją większe optymalizacje ROI, które możesz zrobić gdzie indziej.
Nathaniel Ford

Odpowiedzi:


123

W Javie optymalizacje są zwykle wykonywane na poziomie JVM. W czasie wykonywania maszyna JVM przeprowadza „skomplikowaną” analizę, aby określić, które metody mają być wbudowane. Inlining może być agresywny, a wirtualna maszyna wirtualna Hotspot może w rzeczywistości wstawiać metody nieokończone.

Kompilatory java prawie nigdy nie wbudowują żadnej metody (JVM robi to wszystko w czasie wykonywania). Robią wbudowane stałe czasu kompilacji (np. Końcowe statyczne wartości pierwotne). Ale nie metody.

Aby uzyskać więcej zasobów:

  1. Artykuł: Silnik wydajności Java HotSpot: przykład wstawiania metod

  2. Wiki: Inlining w OpenJDK , nie w pełni zapełniony, ale zawiera linki do przydatnych dyskusji.


15

Nie, w java nie ma funkcji inline . Tak, po umieszczeniu w klasie publicznej publicznej metody statycznej można użyć w dowolnym miejscu kodu. Kompilator java może wykonywać rozwijanie inline w metodzie statycznej lub końcowej, ale nie jest to gwarantowane.

Zwykle takie optymalizacje kodu są wykonywane przez kompilator w połączeniu z JVM / JIT / HotSpot dla często używanych segmentów kodu. Również inne koncepcje optymalizacji, takie jak deklarowanie parametrów w rejestrze, nie są znane w Javie.

Optymalizacji nie można wymusić deklaracją w Javie, ale wykonuje ją kompilator i JIT. W wielu innych językach te deklaracje są często tylko wskazówkami kompilatora (można zadeklarować więcej parametrów rejestru niż ma procesor, pozostałe są ignorowane).

Deklarowanie metod java jako statyczne, końcowe lub prywatne jest również wskazówką dla kompilatora. Powinieneś go używać, ale bez gwarancji. Wydajność Java jest dynamiczna, a nie statyczna. Pierwsze wywołanie systemu jest zawsze powolne z powodu ładowania klas. Następne wywołania są szybsze, ale w zależności od pamięci i czasu wykonania, najczęściej używane wywołania są optymalizowane w działającym systemie, więc serwer może stać się szybszy w trakcie działania!


3
finalnie mają wpływu na inlining JIT
Steve Kuo

1
+1, Ale jak możemy sprawdzić, czy skompilowana wersja metody jest wbudowana?
Pacerier,

@Pacerier Ale po co sprawdzać, czy coś jest wstawione?
Arne Burmeister

14

Java nie umożliwia ręcznego sugerowania, że ​​metoda powinna być wbudowana. Jak @notnoop mówi w komentarzach, wstawianie jest zwykle wykonywane przez maszynę JVM w czasie wykonywania.


3
Większość kompilatorów java nigdy nie wywołuje metod wbudowanych. Przeważnie to robi JVM.
notnoop

Dziękuję za wyjaśnienie. Nie byłem pewien, w której dokładnie fazie się to wydarzyło. Zmienię swój post, aby to odzwierciedlić.
Thomas Owens,

@ThomasOwens tak, ale nie jest to publicznejdk.internal.vm.annotation.ForceInline
Eugene

4

To, co powiedziałeś powyżej, jest poprawne. Czasami ostateczne metody są tworzone jako wbudowane, ale nie ma innego sposobu, aby jawnie utworzyć funkcję wbudowaną w java.


5
Nie ma gwarancji, że ostateczne metody będą wbudowane.
Thomas Owens,

4
W HotSpot dodawanie finalnie ma nawet znaczenia, czy metoda jest wbudowana, czy nie.
Tom Hawtin - tackline

4
@Thomas - dlatego powiedziałem „Czasami ostateczne metody ...”
GreenieMeanie

@ TomHawtin-tackline czy masz wiarygodne źródło informacji? O ile wiem, ostateczne metody mogą być wstawiane bez stosowania ochrony typu, co oznacza, że ​​modyfikator sprawia, że ​​wstawianie metody jest bardziej wydajne niż bez modyfikatora. Wiem, że Jikes RVM bierze to pod uwagę, decydując się na inline. Czy jesteś pewien, że HotSpot nie robi czegoś podobnego?
Jannik Jochem

2

Przykład z życia:

public class Control {
    public static final long EXPIRED_ON = 1386082988202l;
    public static final boolean isExpired() {
        return (System.currentTimeMillis() > EXPIRED_ON);
    }
}

Następnie w innych klasach mogę wyjść, jeśli kod wygasł. Jeśli odwołuję się do zmiennej EXPIRED_ON z innej klasy, stała jest wbudowana w kod bajtowy, co bardzo utrudnia śledzenie wszystkich miejsc w kodzie, które sprawdzają datę ważności. Jeśli jednak inne klasy wywołują metodę isExpired (), wywoływana jest właściwa metoda, co oznacza, że ​​haker może zastąpić metodę isExpired inną, która zawsze zwraca wartość false.

Zgadzam się, byłoby bardzo miło zmusić kompilator do wstawienia statycznej metody końcowej do wszystkich klas, które się do niej odwołują. W takim przypadku nie musisz nawet dołączać klasy Control, ponieważ nie byłaby potrzebna w czasie wykonywania.

Z moich badań wynika, że ​​nie można tego zrobić. Być może niektóre narzędzia Obfuscator mogą to zrobić lub możesz zmodyfikować proces kompilacji, aby edytować źródła przed kompilacją.

Jeśli chodzi o udowodnienie, czy metoda z klasy Control jest umieszczona w linii w innej klasie podczas kompilacji, spróbuj uruchomić drugą klasę bez klasy Control w ścieżce klas.


2

Cóż, istnieją metody, które można nazwać metodami „inline” w java, ale zależą one od jvm. Po kompilacji, jeśli kod maszynowy metody ma mniej niż 35 bajtów, zostanie natychmiast przeniesiony do metody wbudowanej, jeśli kod maszynowy metody jest mniejszy niż 325 bajtów, może zostać przeniesiony do metody wbudowanej, w zależności od jvm.


1
Są to domyślne wartości dla maszyny wirtualnej Oracle, patrz docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
rmuller

0

więc wygląda na to, że nie ma, ale możesz użyć tego obejścia, używając guawy lub równoważnej implementacji klasy funkcji, ponieważ ta klasa jest niezwykle prosta, np .:

    assert false : new com.google.common.base.Function<Void,String>(){
        @Override public String apply(Void input) {
            //your complex code go here
            return "weird message";
        }}.apply(null);

tak, to jest martwy kod tylko po to, aby zilustrować, jak utworzyć złożony blok kodu (w obrębie {}), aby zrobić coś tak specyficznego, że nie powinno nam przeszkadzać w tworzeniu żadnej metody do tego celu, AKA inline!


Wydaje się, że to rozsądny pomysł. Czy masz wersję tego, która nie korzysta ze wspólnych bibliotek Google?
ragerdl

0

Java9 ma kompilator „wyprzedzający czas”, który przeprowadza kilka optymalizacji w czasie kompilacji, a nie w czasie wykonywania, co może być postrzegane jako wbudowane.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.