Co robi kompilator just-in-time (JIT)?

Odpowiedzi:

518

Kompilator JIT jest uruchamiany po uruchomieniu programu i kompiluje kod (zwykle kod bajtowy lub instrukcje VM) w locie (lub jak to się nazywa w odpowiednim momencie) w formie, która jest zwykle szybsza, zazwyczaj natywna jednostka centralna hosta zestaw instrukcji. JIT ma dostęp do dynamicznych informacji o środowisku wykonawczym, podczas gdy standardowy kompilator tego nie robi i może dokonywać lepszych optymalizacji, takich jak często używane funkcje wstawiania.

Jest to przeciwieństwo tradycyjnego kompilatora, który kompiluje cały kod do języka maszynowego przed pierwszym uruchomieniem programu.

Parafrazując, konwencjonalne kompilatory budują cały program jako plik EXE PRZED pierwszym uruchomieniem. W przypadku programów w nowszym stylu zestaw jest generowany z pseudokodem (kod p). Dopiero po uruchomieniu programu w systemie operacyjnym (np. Dwukrotne kliknięcie jego ikony) kompilator (JIT) uruchomi się i wygeneruje kod maszynowy (kod m), który zrozumie procesor oparty na procesorze Intel lub cokolwiek innego.

Mark Cidade
źródło
16
I w przeciwieństwie do interpretowanego kodu, który natychmiast uruchamia instrukcje bajtecode lub VM bezzwłocznie, ale uruchamia instrukcje wolniej niż język maszynowy.
Aaron,
3
JIT jest często używany z interpretowanym kodem w celu konwersji go na język maszynowy, ale tak, kod czysto interpretowany (bez JIT) jest powolny. Nawet kod bajtowy Java bez JITtera jest naprawdę wolny.
Mark Cidade,
48
Jednak celem nie musi być kod maszynowy. JRuby ma kompilator JIT, który po kilku wywołaniach skompiluje kod źródłowy Ruby do kodu bajtowego Java. Następnie, po kilku kolejnych wywołaniach, kompilator JVM JIT uruchamia się i kompiluje kod bajtowy do kodu natywnego.
Jörg W Mittag,
4
Warto zauważyć, że jak wspomina Jörg, JIT niekoniecznie jest wywoływany od razu. Często kod będzie interpretowany, dopóki nie zostanie ustalone, że warto JITting. Ponieważ JITting może wprowadzać opóźnienia, może NIE być szybsze NIE JIT jakiegoś kodu, jeśli jest rzadko używany, dlatego szybka odpowiedź jest ważniejsza niż całkowity czas działania.
Adam Jaskiewicz
3
@ErikReppen: Jeśli pojawi się nowa maszyna, kompilacja i optymalizacja programu dla tej nowej maszyny przy użyciu konwencjonalnego kompilatora prawdopodobnie da wyniki szybciej niż JIT. Z drugiej strony, JIT zoptymalizowany dla tej nowej maszyny będzie mógł zoptymalizować wydajność kodu opublikowanego przed wynalezieniem tej nowej maszyny .
supercat
255

Na początku kompilator był odpowiedzialny za przekształcenie języka wysokiego poziomu (zdefiniowanego jako wyższy poziom niż asembler) w kod obiektowy (instrukcje maszynowe), który następnie zostałby połączony (przez linker) w plik wykonywalny.

W pewnym momencie ewolucji języków kompilatory skompilują język wysokiego poziomu w pseudo-kod, który zostanie następnie zinterpretowany (przez interpretera) w celu uruchomienia programu. To wyeliminowało kod obiektowy i pliki wykonywalne oraz pozwoliło na przenoszenie tych języków na wiele systemów operacyjnych i platform sprzętowych. Pascal (skompilowany do kodu P) był jednym z pierwszych; Java i C # to nowsze przykłady. Ostatecznie termin P-Code został zastąpiony kodem bajtowym, ponieważ większość pseudo-operacji ma długość bajtu.

Kompilator Just-In-Time (JIT) jest funkcją interpretera wykonawczego, który zamiast interpretować kod bajtowy za każdym razem, gdy wywoływana jest metoda, kompiluje kod bajtowy w instrukcjach kodu maszynowego uruchomionego komputera, a następnie wywołuje to zamiast tego kod obiektu. Idealnie sprawność działania kodu obiektowego przezwycięży nieefektywność ponownej kompilacji programu przy każdym uruchomieniu.

Craig Trader
źródło
5
Jednak wyrażenie „kompilator Just-In-Time (JIT) jest cechą interpretera wykonawczego” powoduje zamieszanie; np. - stackoverflow.com/questions/16439512/…
Stephen C
11
W rzeczywistości JIT był dodatkiem i nadal można go wyłączyć za pomocą parametru -Xint dla Javy, więc jest to tylko funkcja.
Craig Trader
3
Nie do końca się zgadzam. JIT nie jest ewolucją - jest alternatywą dla klasycznych kompilatorów.
i486
1
JIT jest krokiem ewolucyjnym od mechanicznych przełączników do okablowania do określenia kryteriów wyszukiwania poprzez powiedzenie „OK Google” na smartfonie. Obecny JIT dostępny jako część Javy 7/8 przeskakuje i wykracza poza to, co było dostępne jako część Javy 2 - to także ewolucja.
Craig Trader
1
@ i486 - Sun / Oracle (AFAIK) nigdy nie wysyłały klasycznego („z wyprzedzeniem”) kompilatora dla Java, który generuje kod macierzysty. Trudno jest argumentować, że JIT jest alternatywą ... kiedy wydaje im się, że jest to alternatywa, której nigdy nie wysłano. (Pomijam kompilator AOT GCJ, ponieważ nie miało to nic wspólnego z Sun / Oracle i nie było to również kompletne rozwiązanie. Teraz z pewnością jest nieopłacalne.)
Stephen C
69

JIT - w samą porę samo słowo mówi, kiedy jest potrzebne (na żądanie)

Typowy scenariusz:

Kod źródłowy jest całkowicie konwertowany na kod maszynowy

Scenariusz JIT:

Kod źródłowy zostanie przekonwertowany na język asemblera podobny do struktury [dla ex IL (język pośredni) dla C #, ByteCode dla java].

Kod pośredni jest konwertowany na język maszynowy tylko wtedy, gdy aplikacja potrzebuje wymaganych kodów, są konwertowane tylko na kod maszynowy.

Porównanie JIT vs Non-JIT:

  • W JIT nie cały kod jest konwertowany na kod maszynowy, najpierw niezbędna część kodu zostanie przekonwertowana na kod maszynowy, a następnie jeśli wywoływana metoda lub funkcja nie znajduje się w maszynie, zostanie to zamienione na kod maszynowy ... zmniejsza się obciążenie procesora.

  • Ponieważ kod maszynowy będzie generowany w czasie wykonywania .... kompilator JIT wygeneruje kod maszynowy zoptymalizowany pod kątem uruchamiania architektury procesora maszyny.

Przykłady JIT:

  1. W Javie JIT jest w JVM (Java Virtual Machine)
  2. W C # jest w CLR (Common Language Runtime)
  3. W Androidzie jest w DVM (Dalvik Virtual Machine) lub ART (Android RunTime) w nowszych wersjach.
Durai Amuthan.H
źródło
7
JIT oferuje pewne szczególne zalety w ramach z obsługą prawdziwych typów ogólnych; możliwe jest zdefiniowanie ogólnej metody, która byłaby w stanie wygenerować nieograniczony zakres typów, każdy z nich wymagałby innego kodu maszynowego, ale kod JIT generowałby tylko dla faktycznie produkowanych typów. Natomiast w C ++ kompilator musi generować kod dla wszystkich typów, których program będzie kiedykolwiek używał.
supercat
6
JVM nie koduje JIT przy pierwszym uruchomieniu. Pierwsze kilka razy interpretuje kod bajtowy. Następnie, jeśli ten kod działa wystarczająco często, może zadecydować o zawracaniu mu głowy JIT.
ninjalj
1
Mówisz, że JIT w Javie to JVM. Jednak już dostarczamy skompilowany kod do JVM, prawda? Więc to kompiluje to znowu?
Koray Tugay
@KorayTugay - Zapewniamy Bytecodes do JVM, a JVM konwertuje część tego kodu na kod maszynowy na żądanie. Więc zasoby są zapisywane.
Durai Amuthan.H
1
W Javie JIT nie jest JVM. To tylko część tego.
dzieje się
25

Jak wspomnieli inni

JIT oznacza Just-in-Time, co oznacza, że ​​kod jest kompilowany, gdy jest potrzebny, a nie przed uruchomieniem.

Aby dodać punkt do powyższej dyskusji, JVM przechowuje informacje o tym, ile razy funkcja jest wykonywana. Jeśli liczba ta przekroczy predefiniowany limit, JIT kompiluje kod do języka maszynowego, który może być bezpośrednio wykonany przez procesor (w przeciwieństwie do zwykłego przypadku, w którym javac kompiluje kod do kodu bajtowego, a następnie java - interpreter interpretuje ten kod bajtowy linia po linii konwertuje go na kod maszynowy i wykonuje).

Również przy następnym obliczeniu tej funkcji ponownie zostanie wykonany ten sam skompilowany kod, w przeciwieństwie do normalnej interpretacji, w której kod jest interpretowany ponownie wiersz po wierszu. Dzięki temu wykonanie jest szybsze.

Aniket Thakur
źródło
14

Kompilator JIT kompiluje tylko bajt-kod do równoważnego kodu macierzystego przy pierwszym uruchomieniu. Przy każdym kolejnym wykonaniu JVM wykorzystuje jedynie skompilowany już kod macierzysty w celu optymalizacji wydajności.

wprowadź opis zdjęcia tutaj

Bez kompilatora JIT interpreter JVM tłumaczy kod bajt wiersz po wierszu, aby wyglądał tak, jakby wykonywana była aplikacja natywna.

wprowadź opis zdjęcia tutaj

Źródło


źródło
1
Moja interpretacja JIT polega na tym, że działa on jak zapamiętywanie, w którym często używane funkcje są „przechowywane”, a koszt kompilacji z kodu bajtowego Java do natywnego kodu zależnego od ISA jest pomijany. Jeśli jest to poprawne, dlaczego Java nie kompiluje się całkowicie do kodu natywnego od samego początku? Zmniejszyłoby to jakąkolwiek kompilację w czasie wykonywania i uczyniłoby javę „natywną” dla maszyny?
Michael Choi
12

JIT oznacza Just-in-Time, co oznacza, że ​​kod jest kompilowany, gdy jest potrzebny, a nie przed uruchomieniem.

Jest to korzystne, ponieważ kompilator może generować kod zoptymalizowany dla konkretnego komputera. Kompilator statyczny, podobnie jak przeciętny kompilator C, skompiluje cały kod do kodu wykonywalnego na komputerze programisty. Dlatego kompilator wykona optymalizacje w oparciu o pewne założenia. Może kompilować się wolniej i wykonywać więcej optymalizacji, ponieważ nie spowalnia wykonywania programu przez użytkownika.

Brian Lyttle
źródło
Dlaczego skompilowane kody nie są przechowywane gdzieś na komputerze użytkownika, więc przy następnym uruchomieniu aplikacji JIT nie musi ich ponownie kompilować?
omerfarukdogan
Dobre obserwacje. Można to zrobić, ale to, czy rzeczywiście jest korzystne, zależy od platformy i użycia aplikacji. Optymalizacja JIT niekoniecznie jest taka sama jak optymalizacja offline lub optymalizacja z wyprzedzeniem, więc korzyścią może być tylko „nie JITting”, co może, ale może nie pomóc.
Brian Lyttle
9

Po wygenerowaniu kodu bajtowego (który jest neutralny dla architektury) przez kompilator Java, wykonanie będzie obsługiwane przez JVM (w Javie). Kod bajtu zostanie załadowany do JVM przez moduł ładujący, a następnie każda instrukcja bajtu zostanie zinterpretowana.

Kiedy musimy wywoływać metodę wiele razy, musimy interpretować ten sam kod wiele razy, co może zająć więcej czasu, niż jest to konieczne. Mamy więc kompilatory JIT (just-in-time). Po załadowaniu bajtu do JVM (czas jego działania) cały kod zostanie skompilowany, a nie zinterpretowany, co pozwoli zaoszczędzić czas.

Kompilatory JIT działają tylko w czasie wykonywania, więc nie mamy żadnych danych binarnych.

Użytkownik
źródło
2
Cały kod nie jest kompilowany po załadowaniu do JVM, ponieważ jest niewiele informacji (czytaj: przewodnik) na temat tego, jak przejść kompilację. Pamiętaj, że wydajność jest ostatecznym celem. JIT jest raczej selektywny: monitorowanie i wybór najpopularniejszych metod optymalizacji. I robi to do momentu osiągnięcia maksymalnego poziomu optymalizacji dla poszczególnych metod.
Yaw Boakye,
7

Just In Time Compiler (JIT):
Kompiluje bytecodes java do instrukcji maszynowych tego konkretnego procesora.

Na przykład, jeśli w naszym kodzie Java jest instrukcja pętli:

while(i<10){
    // ...
    a=a+i;
    // ...
 }

Powyższy kod pętli działa 10 razy, jeśli wartość i wynosi 0.

Nie jest konieczne wielokrotne kompilowanie kodu bajtowego 10 razy, ponieważ ta sama instrukcja będzie wykonywana 10 razy. W takim przypadku konieczne jest skompilowanie tego kodu tylko raz, a wartość można zmienić wymaganą liczbę razy. Tak więc kompilator Just In Time (JIT) śledzi takie instrukcje i metody (jak wspomniano powyżej) i kompiluje takie fragmenty kodu bajtowego w kodzie maszynowym, aby uzyskać lepszą wydajność.

Innym podobnym przykładem jest wyszukiwanie wzorca za pomocą „Wyrażenia regularnego” na liście ciągów / zdań.

Kompilator JIT nie kompiluje całego kodu do kodu maszynowego. Kompiluje kod, który ma podobny wzorzec w czasie wykonywania.

Przeczytaj dokumentację Oracle na temat Zrozumienia JIT, aby przeczytać więcej.

Anands23
źródło
„Nie jest konieczne wielokrotne kompilowanie kodu bajtowego 10 razy, ponieważ ta sama instrukcja będzie wykonywana 10 razy” - a co ze zwykłym kompilatorem? Czy kompiluje ten kawałek kilka razy?
TT_
4

Masz kod, który jest skompilowany do jakiegoś IL (języka pośredniego). Po uruchomieniu programu komputer nie rozumie tego kodu. Rozumie tylko natywny kod. Tak więc kompilator JIT kompiluje Twoją IL w natywnym kodzie w locie. Robi to na poziomie metody.

Charles Graham
źródło
2
Co masz na myśli mówiąc „poziom metody”?
Koray Tugay
4

Wiem, że to stary wątek, ale optymalizacja środowiska wykonawczego to kolejna ważna część kompilacji JIT, która nie wydaje się tutaj omawiana. Zasadniczo kompilator JIT może monitorować uruchamiany program, aby określić sposoby poprawy wykonania. Następnie może wprowadzać te zmiany w locie - podczas działania. Optymalizacja Google JIT (javaworld ma na ten temat całkiem niezły artykuł ).

eze
źródło
3

Kompilator „just in time” (JIT) to oprogramowanie, które pobiera nieobsługiwane dane wejściowe i zwraca odpowiedni kod maszynowy do wykonania. Na przykład:

Intermediate representation    JIT    Native machine code for the current CPU architecture

     Java bytecode            --->        machine code
     Javascript (run with V8) --->        machine code

Konsekwencją tego jest to, że dla określonej architektury CPU musi być zainstalowany odpowiedni kompilator JIT.

Kompilator różnic, interpreter i JIT

Chociaż mogą istnieć wyjątki, gdy chcemy przekształcić kod źródłowy w kod maszynowy, możemy użyć:

  1. Kompilator : pobiera kod źródłowy i zwraca plik wykonywalny
  2. Interpretator : Wykonuje instrukcję programu według instrukcji. Pobiera wykonywalny segment kodu źródłowego i zamienia ten segment w instrukcje maszynowe. Proces ten powtarza się, aż cały kod źródłowy zostanie przekształcony w instrukcje maszyny i wykonany.
  3. JIT : Możliwych jest wiele różnych implementacji JIT, jednak JIT jest zwykle kombinacją kompilatora i tłumacza. JIT najpierw przekształca dane pośrednie (np. Kod bajtowy Java), które otrzymuje na język maszynowy poprzez interpretację. JIT często może wykryć, kiedy pewna część kodu jest często wykonywana, i skompiluje tę część w celu szybszego wykonania.
Willem van der Veen
źródło
2

Jit to skrót od jit kompilatora to program, który zamienia kod bajtu java w instrukcję, która może być wysłana bezpośrednio do procesora.

Korzystanie z kompilatora java just in time (tak naprawdę drugiego kompilatora) na konkretnej platformie systemowej jest zgodne z kodem bajtowym w określonym kodzie systemowym, gdy kod zostanie ponownie skompilowany przez kompilator jit, zwykle będzie działał szybciej na komputerze.

Kompilator just-in-time jest dostarczany z maszyną wirtualną i jest używany opcjonalnie. Kompiluje kod bajtowy w specyficzny dla platformy kod wykonywalny, który jest natychmiast wykonywany.

użytkownik3459027
źródło
2

Kompilacja just-in-time (JIT) (także tłumaczenie dynamiczne lub kompilacja w czasie wykonywania) to sposób wykonywania kodu komputerowego, który obejmuje kompilację podczas wykonywania programu - w czasie wykonywania - a nie przed jego wykonaniem .

Kompilacja IT to połączenie dwóch tradycyjnych podejść do tłumaczenia na kod maszynowy - kompilacja z wyprzedzeniem (AOT) i interpretacja - i łączy w sobie zalety i wady obu tych metod. Kompilacja JIT łączy szybkość skompilowanego kodu z elastycznością interpretacji .

Rozważmy JIT używany w JVM,

Na przykład kompilatory HotSpot JVM JIT generują dynamiczne optymalizacje. Innymi słowy, podejmują decyzje optymalizacyjne podczas działania aplikacji Java i generują wysokowydajne instrukcje natywnej maszyny skierowane do podstawowej architektury systemu.

Po wybraniu metody do kompilacji JVM podaje swój kod bajtowy do kompilatora Just-In-Time (JIT). JIT musi zrozumieć semantykę i składnię kodu bajtowego, zanim będzie mógł poprawnie skompilować metodę. Aby pomóc kompilatorowi JIT w analizie metody, jego kod bajtowy jest najpierw przeformułowany w wewnętrznej reprezentacji zwanej drzewkami śledzenia, która bardziej przypomina kod maszynowy niż kod bajtowy. Następnie przeprowadza się analizy i optymalizacje drzew tej metody. Na koniec drzewa są tłumaczone na kod macierzysty.

Drzewo śledzenia to struktura danych używana w kompilacji kodu programowego w środowisku wykonawczym. Drzewa śledzenia są używane w typie kompilatora „just in time”, który śledzi kod wykonywany podczas hotspotów i kompiluje go. Zobacz to .

Patrz:

główny
źródło
1

Kompilator inny niż JIT pobiera kod źródłowy i przekształca go w specyficzny dla maszyny kod bajtowy w czasie kompilacji. Kompilator JIT pobiera kod bajtowy agnostyczny wygenerowany w czasie kompilacji i przekształca go w kod bajtowy specyficzny dla maszyny w czasie wykonywania. Kompilator JIT, z którego korzysta Java, pozwala na uruchomienie jednego pliku binarnego na wielu platformach bez modyfikacji.


źródło
0

20% kodu bajtowego jest używane przez 80% czasu. Kompilator JIT pobiera te statystyki i optymalizuje ten 20% kodu bajtów, aby działał szybciej, dodając metody wbudowane, usuwając nieużywane blokady itp., A także tworząc kod bajtowy specyficzny dla tego komputera. Cytuję ten artykuł, który okazał się przydatny. http://java.dzone.com/articles/just-time-compiler-jit-hotspot

Santosh budhe
źródło
Nie jestem pewien, dlaczego oznaczono to jako -1. Myślę, że chodzi tutaj o to, że statystyki optymalizacji są używane do optymalizacji.
eze
Tak, ale odpowiedź nie brzmiała tak. Dosłownie, JIT nie optymalizuje najgorętszych 20% kodu.
mabraham
0

JIT odnosi się do silnika wykonawczego w kilku implementacjach JVM, który jest szybszy, ale wymaga więcej pamięci, jest kompilatorem just-in-time. W tym schemacie kody bajtów metody są kompilowane do natywnego kodu maszynowego przy pierwszym wywołaniu metody. Natywny kod maszynowy dla tej metody jest następnie buforowany, dzięki czemu można go ponownie użyć przy następnym wywołaniu tej samej metody.

Venkata Santhosh Piduri
źródło
2
Unikałbym odpowiedzi na takie pytanie, jeśli nie dostarczysz czegoś nowego / lepszego. Jeśli pojawi się jakakolwiek reakcja, prawdopodobnie jest to opinia negatywna lub krytyka: Twoja odpowiedź jest nieprecyzyjna. „JIT” nie ogranicza się do wirtualnej maszyny Java , „szybszy, ale zużywa więcej pamięci” jest prawdopodobnym efektem, ale nie jest nieodłączny od koncepcji JIT, a metody często nie są kompilowane przy pierwszym wywołaniu, a raczej po kilku, gdy staje się jasne, że spędzanie czasu na JIT'ingu jest ogólnie korzystne.
zapl
0

JVM faktycznie wykonuje kroki kompilacji w czasie wykonywania ze względu na wydajność. Oznacza to, że Java nie ma czystej separacji wykonywania i kompilacji. Najpierw wykonuje tak zwaną kompilację statyczną od kodu źródłowego Java do kodu bajtowego. Następnie ten kod bajtowy jest przekazywany do maszyny JVM w celu wykonania. Ale wykonywanie kodu bajtowego jest powolne, więc JVM mierzy, jak często jest uruchamiany kod bajtowy, a gdy wykryje „gorący punkt” kodu, który jest uruchamiany bardzo często, wykonuje dynamiczną kompilację od kodu bajtowego do kodu maszynowego kodu „hotspot” (profiler punktu aktywnego). Tak skutecznie dzisiaj programy Java są uruchamiane przez wykonanie kodu maszynowego.

cześć
źródło
0

Kompilator Just In Time znany również jako kompilator JIT służy do poprawy wydajności w Javie. Jest domyślnie włączony. Jest to kompilacja wykonywana w czasie wykonywania raczej wcześniej. Java spopularyzowała użycie kompilatora JIT, włączając go do JVM.

Ganesh Giri
źródło