Dlaczego Java jest szybsza przy użyciu JIT a kompilacji do kodu maszynowego?

Słyszałem, że Java musi używać JIT, aby być szybkim. To ma sens w porównaniu z interpretacją, ale dlaczego ktoś nie może stworzyć kompilatora, który generuje szybki kod w Javie? Wiem o gcj, ale nie sądzę, że jego wyjście jest zazwyczaj szybsze niż np. Hotspot.

Czy są rzeczy w języku, które sprawiają, że to trudne? Myślę, że sprowadza się to tylko do tych rzeczy:

  • odbicie
  • Classloading

Kim jestem zaginęła? Jeśli uniknę tych funkcji, czy będzie możliwe skompilowanie kodu Javy raz do natywnego kodu maszynowego i zostanie zrobione?

 48
Author: Adam Goode, 2009-12-10

10 answers

Prawdziwym zabójcą dla każdego kompilatora AOT jest:

Class.forName(...)

Oznacza to, że nie można napisać kompilatora AOT, który obejmuje Wszystkie Programy Java, ponieważ dostępne są tylko w czasie wykonywania informacje o charakterystyce programu. Można to jednak zrobić na podzbiorze Javy, co moim zdaniem robi gcj.

Innym typowym przykładem jest zdolność JIT do inline metod, takich jak getX() bezpośrednio w metodach wywołujących, jeśli okaże się, że jest to bezpieczne i cofanie go w razie potrzeby, nawet jeśli programista wyraźnie nie pomógł, informując, że metoda jest ostateczna. JIT może zobaczyć, że w uruchomionym programie dana metoda nie jest nadpisana i dlatego w tym przypadku może być traktowana jako ostateczna. To może być inne w następnym inwokacji.

 22
Author: Thorbjørn Ravn Andersen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 07:20:45

Kompilator JIT może być szybszy, ponieważ kod maszynowy jest generowany na dokładnie tej samej maszynie, na której będzie również wykonywany. Oznacza to, że JIT ma najlepsze możliwe informacje dostępne dla niego emitować zoptymalizowany kod.

Jeśli wstępnie skompilujesz kod bajtowy do kodu maszynowego, kompilator nie może zoptymalizować dla docelowej maszyny(maszyn), tylko maszyny kompilacyjnej.

 34
Author: Andrew Hare,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 04:52:26

Wkleję ciekawą odpowiedź udzieloną przez Jamesa Goslinga w książce Masterminds of Programming .

Słyszałem, że skutecznie masz dwa Kompilatory w świat Javy. Masz kompilator do kodu bajtowego Javy, a następnie masz Twój JIT, który w zasadzie rekompiluje wszystko jeszcze raz. Wszystkie Twoje przerażające optymalizacje są w JIT .

Dokładnie. These days we ' re bicie naprawdę dobre C i C++ Kompilatory prawie zawsze. Kiedy ty przejdź do dynamicznego kompilatora, otrzymasz dwie zalety gdy kompilator jest / align = "left" / Jeden Czy wiesz dokładnie jaki chipset uciekasz. Tyle razy, kiedy ludzie kompilują kawałek C kod, muszą go skompilować, aby uruchomić na generic x86 Architektura. Prawie żaden z binaria, które dostajesz, są szczególnie dobrze dostrojony do każdego z nich. Pobierasz najnowsza Kopia Mozilla i będzie uruchom na prawie każdym Intelu procesor architektury. Jest prawie jeden binarny Linux. To dość ogólne, i jest skompilowany z GCC, czyli niezbyt dobry kompilator C.

Kiedy HotSpot działa, wie dokładnie na jakim chipsecie pracujesz. Informatyka wie dokładnie, jak działa pamięć podręczna. Informatyka wie dokładnie, jak hierarchia pamięci działa. Doskonale wie, w jaki sposób wszystkie blokady rurociągów działają w procesorze. Wie jaki zestaw instrukcji rozszerzenia to chip ma. Informatyka optymalizuje dokładnie dla jakiej maszyny stoi. Potem druga połowa czy rzeczywiście widzi aplikacja jest uruchomiona. Jest w stanie mieć statystyki, które wiedzą, które rzeczy są ważne. Jest w stanie inline rzeczy, które kompilator C może nigdy. Takie rzeczy, które się inlined in the Java world is pretty niesamowite. A potem przyczepiasz się do tego sposób zarządzania pamięcią masową współcześni śmieciarze. Z nowoczesne śmieci kolektor, magazyn przydział jest niezwykle szybki.

Masterminds of Programming

 27
Author: Edwin Dalorzo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-09 16:40:16

Kompilator JIT Javy jest również leniwy i adaptacyjny.

Lazy

Będąc leniwym kompiluje metody tylko wtedy, gdy do nich dociera, zamiast kompilować cały program(bardzo przydatne, jeśli nie używasz części programu). Ładowanie klas faktycznie pomaga przyspieszyć JIT, pozwalając mu ignorować klasy, na które jeszcze się nie natknął.

Adaptive

Będąc adaptacyjnym emituje szybką i brudną wersję kodu maszynowego, a następnie wraca i wykonuje zadanie, jeśli to metoda jest często stosowana.

 22
Author: Luke Quinane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 04:59:21

W końcu sprowadza się to do tego, że posiadanie większej ilości informacji umożliwia lepsze optymalizacje. W tym przypadku, JIT ma więcej informacji o rzeczywistej maszynie, na której działa kod (jak wspomniał Andrew), a także wiele informacji o uruchomieniu, które nie są dostępne podczas kompilacji.

 11
Author: Tal Pressman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 04:55:57

Zdolność Javy do inline przekraczania granic wirtualnych metod i wydajnego wysyłania interfejsów wymaga analizy środowiska uruchomieniowego przed kompilacją - innymi słowy wymaga JIT. Ponieważ wszystkie metody są wirtualne, a interfejsy są używane "wszędzie", robi to dużą różnicę.

 6
Author: Sam Harwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 04:54:50

W teorii kompilator JIT ma przewagę nad AOT , jeśli ma wystarczająco dużo czasu i dostępnych zasobów obliczeniowych. Na przykład, jeśli masz aplikację korporacyjną działającą przez wiele dni i miesięcy na wieloprocesorowym serwerze z dużą ilością pamięci RAM, kompilator JIT Może wyprodukować lepszy kod niż jakikolwiek kompilator AOT.

Teraz, jeśli masz aplikację komputerową, rzeczy takie jak szybkie uruchamianie i początkowy czas reakcji (gdzie świeci AOT) stają się ważniejsze, plus komputer może nie mieć wystarczające zasoby dla najbardziej zaawansowanych optymalizacji.

A jeśli masz wbudowany system z ograniczonymi zasobami, JIT nie ma szans przeciwko AOT.

Jednak powyższe wszystko było teorią. W praktyce tworzenie tak zaawansowanego kompilatora JIT jest o wiele bardziej skomplikowane niż porządny AOT. A może jakieś praktyczne dowody?

 5
Author: Dmitry Leskov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 06:02:22

JITs może zidentyfikować i wyeliminować pewne warunki, które mogą być znane tylko w czasie wykonywania. Głównym przykładem jest eliminacja wywołań wirtualnych używanych przez nowoczesne maszyny wirtualne - np. gdy JVM znajdzie instrukcję invokevirtual lub invokeinterface, jeśli załadowana została tylko jedna klasa nadpisująca wywołaną metodę, maszyna wirtualna może faktycznie uczynić to wirtualne wywołanie statycznym i w ten sposób może je wbudować. Do programu C, z drugiej strony Wskaźnik funkcji jest zawsze wskaźnikiem funkcji, a wywołanie do niego nie może być inlined (w ogólnym case, anyway).

W tej sytuacji JVM jest w stanie wprowadzić wirtualne wywołanie:
interface I { 
    I INSTANCE = Boolean.getBoolean("someCondition")? new A() : new B();
    void doIt(); 
}
class A implements I { 
    void doIt(){ ... } 
}
class B implements I { 
    void doIt(){ ... } 
}
// later...
I.INSTANCE.doIt();

Zakładając, że nie tworzymy instancji A lub B gdzie indziej i że someCondition jest ustawione na true, JVM wie, że wywołanie {[7] } zawsze oznacza A.doIt, i dlatego może uniknąć przeszukiwania tabeli metod, a następnie inline wywołania. Podobna konstrukcja w środowisku bez Jittowym nie byłaby inlinable.

 5
Author: gustafc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 07:55:02

Myślę, że fakt, że oficjalny kompilator Javy jest kompilatorem JIT jest dużą częścią tego. Ile czasu poświęcono na optymalizację JVM a kompilator kodu maszynowego dla Javy?

 2
Author: Brendan Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-10 07:27:40

Dimitry Leskov jest absolutnie tutaj.

Wszystko to tylko teoria, co może przyspieszyć JIT, implementacja każdego scenaro jest prawie niemożliwa. Poza tym, ze wzglÄ ™ du na fakt, Ĺźe mamy tylko garstkä ™ róşnych zestawăłw instrukcji na procesorach x86_64, niewiele moĹźna zyskać, kierujÄ ... c kaĹźdy zestaw instrukcji na aktualnym CPU. Zawsze kieruję się zasadą targetowania x86_64 i SSE4.2 przy budowaniu aplikacji o znaczeniu krytycznym w kodzie natywnym. Podstawy Javy struktura powoduje mnóstwo ograniczeń, JNI może pomóc ci pokazać, jak nieefektywne jest to, JIT tylko słodzi to, czyniąc go ogólnie szybszym. Poza tym, że każda funkcja domyślnie jest wirtualna, używa również typów klas w czasie wykonywania, w przeciwieństwie do na przykład C++. C++ ma tutaj wielką zaletę, jeśli chodzi o wydajność, ponieważ żaden obiekt klasy nie jest wymagany do załadowania w czasie wykonywania, są to wszystkie bloki danych, które są przydzielane do pamięci i inicjowane tylko na żądanie. W innymi słowy, C++ nie ma typów klas w czasie wykonywania. Klasy Java są rzeczywistymi obiektami, a nie tylko szablonami. Nie pójdę do GC, bo to nieistotne. Ciągi Java są również wolniejsze, ponieważ używają dynamicznego poolingu ciągów, co wymagałoby uruchomienia do każdorazowego wyszukiwania ciągów w tabeli puli. Wiele z tych rzeczy wynika z faktu, że Java nie została zbudowana po to, aby była szybka, więc jej fundament zawsze będzie powolny. Większość języków rodzimych (przede wszystkim C / C++) została specjalnie zbudowana, aby szczupły i podły, bez marnowania pamięci i zasobów. Pierwsze kilka wersji Javy w rzeczywistości były strasznie powolne i marnotrawne dla pamięci, z dużą ilością niepotrzebnych metadanych dla zmiennych i co nie. Jak to jest dzisiaj, JIT jest w stanie produkować szybszy Kod niż języki AOT pozostanie teoria.

Pomyśl o całej pracy, którą JIT musi śledzić, aby wykonać leniwy JIT, zwiększ licznik za każdym razem, gdy wywołana jest funkcja, Sprawdź, ile razy została wywołana.. tak dalej i tak dalej. Prowadzenie JIT zajmuje dużo czasu. Handel w moich oczach nie jest tego wart. To jest tylko na PC

Próbowałeś kiedyś uruchomić Javę na Raspberry i innych urządzeniach wbudowanych? Absolutnie okropny występ. JavaFX na Raspberry? Nawet nie działa... Java i jej JIT jest bardzo daleko od spełnienia wszystkich tego, co reklamuje i teorii ludzie ślepo wypluwają o tym.

 0
Author: Christopher Bekesi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 16:48:15