Dlaczego JVM nie buforuje skompilowanego kodu JIT?


107

Implementacja kanonicznej maszyny JVM firmy Sun stosuje dość wyrafinowaną optymalizację kodu bajtowego, aby uzyskać prawie natywne prędkości wykonywania po kilkukrotnym uruchomieniu kodu.

Pytanie brzmi, dlaczego ten skompilowany kod nie jest zapisywany w pamięci podręcznej na dysku w celu użycia podczas kolejnych zastosowań tej samej funkcji / klasy?

W obecnej formie, za każdym razem, gdy program jest wykonywany, kompilator JIT uruchamia się od nowa, zamiast używać wstępnie skompilowanej wersji kodu. Czy dodanie tej funkcji nie zwiększyłoby znacząco początkowego czasu wykonywania programu, gdy kod bajtowy jest zasadniczo interpretowany?


4
Wątek omawiający ten problem: javalobby.org/forums/thread.jspa?threadID=15812
miku

2
Ale mało prawdopodobne pytanie, które przyciągnie ostateczną odpowiedź.
bmargulies

1
Nie jestem pewien co do „znaczącego” przyspieszenia, ponieważ wtedy musiałbyś załadować JIT z dysku zamiast JIT-a w pamięci. Może to przyspieszyć działanie, ale w poszczególnych przypadkach.
R. Martinho Fernandes

1
Dzięki za świetne odpowiedzi wszystkim! Wszystkie odpowiedzi były równie ważne, więc poszedłem ze społecznością na ten jeden ...
Chinmay Kanchi

To dobre pytanie, jeśli o mnie chodzi :)
Alfred

Odpowiedzi:


25

Bez uciekania się do wycinania i wklejania linku opublikowanego przez @MYYN, podejrzewam, że dzieje się tak, ponieważ optymalizacje, które wykonuje JVM, nie są statyczne, ale raczej dynamiczne, oparte na wzorcach danych i wzorcach kodu. Jest prawdopodobne, że te wzorce danych ulegną zmianie w okresie istnienia aplikacji, powodując, że optymalizacje zapisane w pamięci podręcznej będą mniej niż optymalne.

Potrzebowałbyś więc mechanizmu do ustalenia, czy zapisane optymalizacje były nadal optymalne, w którym to momencie równie dobrze możesz po prostu dokonać ponownej optymalizacji w locie.


6
... lub możesz po prostu zaoferować trwałość jako opcję , tak jak robi to JVM firmy Oracle - umożliwiając zaawansowanym programistom optymalizację wydajności ich aplikacji, kiedy i gdzie po prostu wiedzą, że wzorce się nie zmieniają, na ich odpowiedzialność. Dlaczego nie?!
Alex Martelli,

2
Bo chyba nie warto. Jeśli ani SUN, ani IBM, ani BEA nie uznały, że jest to warte zachodu ze względu na ich wydajne maszyny JVM, będzie ku temu dobry powód. Może ich optymalizacja RT jest szybsza niż Oracle, dlatego Oracle ją buforuje.
skaffman

9
Dlaczego nie przyjąć przechowywanych optymalizacji jako punktu wyjścia, aby wykorzystać to, czego nauczyliśmy się podczas poprzednich uruchomień? Stamtąd JIT może działać jak zwykle i ponownie optymalizować rzeczy. Po zamknięciu kod może zostać ponownie utrwalony i użyty w następnym uruchomieniu jako nowy punkt początkowy.
Puce

1
@Puce Jedynym powodem, o którym mogę pomyśleć, jest to, że AFAIK nie otrzymujesz statystyk profilowania po uruchomieniu zoptymalizowanego kodu. Więc nie miałbyś sposobu, aby poprawić ...
maaartinus

1
Osobiście byłbym w porządku z opcją „po prostu utrzymuj informacje o profilowaniu JIT między uruchomieniami” ze wszystkimi ostrzeżeniami, że „będzie to poprawne tylko z dokładnie tą samą maszyną JVM, tymi samymi danymi itp. I w inny sposób ignorowane”. Biorąc pod uwagę, dlaczego nie zostało to zaimplementowane, spodziewałbym się, że dodatkowa złożoność utrwalania i walidacji danych źródłowych JIT była zbyt duża, aby wykorzystać zasoby z innych projektów. Biorąc pod uwagę wybór między tym strumieniem a strumieniem lambda 8 w języku Java 8, wolałbym raczej mieć to drugie.
Thorbjørn Ravn Andersen

25

JVM firmy Oracle jest rzeczywiście udokumentowane, aby to robić - cytując Oracle,

kompilator może korzystać z modelu rozwiązywania klas Oracle JVM, aby opcjonalnie utrwalać skompilowane metody Java w wywołaniach, sesjach lub instancjach bazy danych. Taka trwałość pozwala uniknąć niepotrzebnych ponownych kompilacji między sesjami lub wystąpieniami, gdy wiadomo, że semantycznie kod Java nie uległ zmianie.

Nie wiem, dlaczego wszystkie zaawansowane implementacje maszyn wirtualnych nie oferują podobnych opcji.


8
Ponieważ inne wyrafinowane maszyny JVM nie mają wielkiego korporacyjnego systemu RDBMS pod ręką do przechowywania rzeczy :)
skaffman

Łał! oznacza to, że kompilacje są czasami buforowane. To jest dobra wiadomość!
Sandeep Jindal

Udokumentowano również, że IBM J9 to robi.
user314104

9
Należy pamiętać, że ta maszyna JVM firmy Oracle znajduje się w bazie danych Oracle, a nie jest pobierana przez firmę Oracle przy zakupie firmy Sun.
Thorbjørn Ravn Andersen


5

Excelsior JET ma buforujący kompilator JIT od wersji 2.0, wydanej w 2001 roku. Co więcej, jego kompilator AOT może przekompilować pamięć podręczną do pojedynczego obiektu DLL / współdzielonego obiektu przy użyciu wszystkich optymalizacji.


3
Tak, ale pytanie dotyczyło kanonicznego JVM, tj. JVM firmy Sun. Doskonale zdaję sobie sprawę, że istnieje kilka kompilatorów AOT dla języka Java, a także innych maszyn JVM buforujących.
Chinmay Kanchi

0

Nie znam faktycznych powodów, nie jestem w żaden sposób zaangażowany w implementację JVM, ale mogę wymyślić kilka prawdopodobnych:

  • Ideą Javy jest bycie językiem do zapisu, który można jednorazowo uruchomić w dowolnym miejscu, a umieszczanie wstępnie skompilowanych rzeczy w pliku klasy jest pewnym naruszeniem tego (tylko „w pewnym sensie”, ponieważ rzeczywisty kod bajtowy nadal tam byłby)
  • Zwiększyłoby to rozmiary plików klas, ponieważ miałbyś tam ten sam kod wiele razy, zwłaszcza jeśli zdarzyło ci się uruchomić ten sam program na wielu różnych maszynach JVM (co nie jest rzadkością, gdy rozważasz różne wersje jako różne maszyny JVM), naprawdę muszę zrobić)
  • Same pliki klas mogą nie być zapisywalne (chociaż byłoby to dość łatwe do sprawdzenia)
  • Optymalizacje JVM są częściowo oparte na informacjach z czasu wykonywania, a przy innych uruchomieniach mogą nie być tak przydatne (chociaż nadal powinny zapewniać pewne korzyści)

Ale naprawdę zgaduję i jak widzisz, nie sądzę, aby którykolwiek z moich powodów był faktycznym zatrzymaniem show. Wydaje mi się, że Sun po prostu nie traktuje tego wsparcia jako priorytetu i być może mój pierwszy powód jest bliski prawdy, ponieważ robienie tego zwykle może również skłonić ludzi do myślenia, że ​​pliki klas Java naprawdę potrzebują osobnej wersji dla każdej maszyny wirtualnej zamiast być wieloplatformowy.

Moim preferowanym sposobem byłoby posiadanie oddzielnego translatora z kodu bajtowego na natywny, którego można by użyć do zrobienia czegoś takiego jawnie wcześniej, tworząc pliki klas, które są jawnie zbudowane dla konkretnej maszyny wirtualnej, z prawdopodobnie oryginalnym kodem bajtowym w nich może również działać z różnymi maszynami wirtualnymi. Ale to prawdopodobnie wynika z mojego doświadczenia: głównie robię Java ME, gdzie naprawdę boli, że kompilator Java nie jest mądrzejszy w kompilacji.


1
w pliku klasy jest miejsce na takie rzeczy, w rzeczywistości było to pierwotnym zamiarem (przechowuj kod JIT jako atrybut w pliku klas).
TofuBeer

@TofuBeer: Dzięki za potwierdzenie. Podejrzewałem, że tak może być (tak bym zrobił), ale nie byłem pewien. Edytowano, aby usunąć to jako możliwy powód.
JaakkoK,

Myślę, że ostatnim pociskiem uderzyłeś w łeb. Inne można obejść, ale myślę, że ta ostatnia część jest głównym powodem, dla którego kod JITed nie jest utrwalony.
Sasha Chedygov

1
Ostatni akapit dotyczący jawnego kompilatora z kodem bajtowym do natywnego jest tym, co obecnie masz w .NET z NGEN ( msdn.microsoft.com/en-us/library/6t9t5wcf(VS.71).aspx ).
R. Martinho Fernandes
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.