Przed startem tego bloku myślałem, że zajęcia o JVMie – tej magicznej maszynce, która przyjmuje nasz skompilowany do poziomu kodu bajtowego program i go uruchamia – to będą techniczne niuanse odpalania apek. Do pewnego stopnia tak było, ale przytłaczającą większość 7 godzinnego bloku poświęciliśmy na wydajność zarządzania pamięcią w Javie.

Gdzie w ekosystemie Javy znajduje się JVM? A no tu:
jvm

WORA, czyli dlaczego Java rządzi

WORA – zapamiętajcie ten akronim. Write Once, Run Anywhere – czyli funkcjonalność, która pozwoliła Javie trafić do biliona (tak, biliona – 12 zer, 1 000 000 000 000) desktopów, 3 bilionów telefonów komórkowych i kolejnych bilionów urządzeń typu drukarki, nawigacje samochodowe, bankomaty i pralki automatyczne. JVM pozwala uruchomić aplikację napisaną w Javie na w zasadzie każdym interfejsie, który posiada wgrany Java Runtime Environment (kombo JVM i bibliotek Javy).

Twórcom Javy (przypomnę tylko, że od wydania pierwowzoru Javy – języka Oak minęło 26 lat, a sama Java liczy sobie 22 lata) u zarania dziejów zależało bowiem na tym, by pominąć różnice w architekturach systemowych i stworzyć uniwersalną platformę. Tak powstał JVM – wirtualna maszyna Javy, która działa poziom wyżej niż natywne kody maszynowe, charakterystyczne dla konkretnych urządzeń czy interfejsów. Sam JVM to nic innego jak … aplikacja. Napisana zresztą w C++.

Co ponadto warto zapamiętać o JVM? Ano to, że sam JVM jest niezależny od kodu źródłowego. To znaczy, że JVM może wykonywać kod bajtowy napisany w Groovym, Scali, Kotlinie czy Javie właśnie. Tak długo, jak język kompiluje się kodu bajtowego Javy, tak uruchomi go JVM.

Co się dzieje w JVM’ie?

W czarnej magicznej skrzynce jaką jest JVM kod bajtowy tłumaczony jest z pomocą interpretera do kodu interpretowanego (temat na osobny wpis) lub z pomocą kompilatora Just in Time do wykonywalnego kodu natywnego (maszynowego). Czyli kodu, który rozumie urządzenie (system) na którym odpalamy apkę. I nasza apka się odpala.

Ale, ale – nie tak prędko. To znaczy, zanim napisałem choć trzy znaki, to większość z naszych amatorskich apek pokroju Hello World zdążyła już wstać i odpalić się w bashu – a więc jest to wszystko szybkie. A o szybkość tu chodzi – o efektywność zarządzania pamięcią. Od tego zacząłem ten wpis, ale – jak widać – wymagało to wszystko sporego wstępu.

I o ile informacje o tym co się dzieje na każdym etapie pracy JVM’a można było do tej pory dosyć prosto uszeregować, tak teraz sprawa się mocno komplikuje. Nie będę udawał, że wiem dużo w niezwykle złożonym zagadnieniu, jakim jest wydajność Javy. Co wiem?
– że do mierzenia wydajności pamięciowej aplikacji napisanych w Javie wykorzystujemy flagi. Podstawowe flagi to: XMX – maksymalny heap i XMS – wartość startowa heap’a (sterty)
– sterta jest niczym innym jak tylko pamięcią, która w czasie wykonywania programu przechowuje twoje obiekty.
– kolejnym komponentem jest Garbage Collector – odśmiecacz – niezwykle zaawansowany kombajn do usuwania nieużywanych obiektów, tak by móc zaalokować na ich miejsce nowe
– w JVM działa też stos – (stack) – który przechowuje tymczasowe zmienne i tymczasowe wyniki działania programu. Dostęp do niego odbywa się za pomocą protokołu LIFO – last in, first out

W dwudniowym bloku o JVM’ie za pomocą ustawiania flagami wielkości sterty i stosu sprawdzaliśmy jak aplikacje zarządzają pamięcią. Kolejny krok to profilowanie działających aplikacji w YourKit Profiler.

To by było na tyle. Następny blok – TDD, już wkrótce.