Implementacje Javy

Kompilator i środowiska wykonawcze

Wynikiem kompilacji programów Javy jest kod pośredni nazywany kodem bajtowym Javy (ang. Java Byte Code). Kod bajtowy jest zestawem instrukcji dla wirtualnej maszyny Javy (ang. Java Virtual Machine: JVM). Interpreter kodu bajtowego Javy umożliwia wykonanie programu. Jego działanie emuluje maszynę wirtualną Javy w pewnym środowisku sprzętowo-programowym. Istnienie wielu interpreterów JVM na różne konfiguracje sprzętowo-programowe gwarantuje realizację zarówno niezależności od nich jak i przenośność oprogramowania napisanego w Javie.

Jak już wspomniano, wykonanie programów nazywanych apletami, przesyłanych przez sieć Internet, polega na uruchomieniu ich za pośrednictwem przeglądarki, w którą wbudowano interpreter kodu bajtowego (do takich przeglądarek należą np.: Microsoft Internet Explorer 3.0 i późniejsze i Netscape Navigator 2.0 i późniejsze, oraz inne). Poniższe rysunki prezentują sposób tworzenia i wykonania programu napisanego w Javie oraz w języku C++.

Rysunek 3-1 Kompilacja i wykonanie programu napisanego w Javie.

Rysunek 3-2 Kompilacja i wykonanie programu napisanego w C++.

Podczas kompilacji plików z kodem Javy (*.java) tworzone są pliki (*.class) zawierające instrukcje kodu bajtowego Javy. Te instrukcje muszą być wykonane przez interpreter kodu bajtowego Javy, wbudowany w przeglądarkę dla apletów lub niezależny od przeglądarki dla aplikacji.

Dzięki wprowadzeniu maszyny wirtualnej osiągnięto następujące cele:

Program piszemy dla maszyny wirtualnej, wykonywany jest on natomiast na komputerze o dowolnej konfiguracji sprzętowo-programowej, dla której istnieją emulatory maszyny wirtualnej (JVM). Zastosowanie maszyny wirtualnej daje nam niezależność od sprzętu, na którym faktycznie wykonywany będzie program napisany w Javie;

Programy w kodzie bajtowym dla maszyny wirtualnej są znacznie mniejsze niż konwencjonalne kody wynikowe programów. Dzieje się tak dlatego, że standardowe funkcje Javy używane przez aplet wbudowane są w przeglądarki, a nie dołączane do apletu. To rozwiązanie zmniejsza rozmiar apletu Javy, który przeważnie ładowany jest z Internetu i w ten sposób skraca się czas samego ładowania. Dalsze skrócenie czasu ładowania następuje dzięki temu, że Java ładuje tylko te klasy, które są jej potrzebne w danej chwili do wykonania tego programu, a następne klasy ładuje tylko w razie potrzeby;

Dzięki zastosowaniu maszyny wirtualnej mamy zapewnione bezpieczeństwo programowe. Jeśli program jest wykonywany w trybie "rodzimym" (ang. parent) procesora, każda operacja systemu lub przeglądarki może być wykorzystana przez "hackerów", którzy szukają drogi dostępu do maszyny klienta. Programy Javy nie mają takiej elastyczności. Programy Javy są wykonywane na maszynie wirtualnej Javy stworzonej przez przeglądarkę. Podczas wykonywania programu przeglądarka obserwuje kroki programu, więc mamy pewność, że program nie będzie miał dostępu do zasobów i operacji, do których nie ma prawa.

Słabą stroną programów napisanych w Javie jest mała szybkość ich wykonywania spowodowana procesem interpretowania kodu bajtowego w przeglądarce. Kod bajtowy Javy nie jest wykonywany tak szybko, jak zwykły, napisany w kodzie maszynowym procesora program. Aby rozwiązać ten problem wprowadzono "kompilację w locie" (ang. Just­in­Time compilation JIT) kodu bajtowego do kodu maszynowego danego procesora. Kiedy przeglądarka ładuje pierwszy raz aplet Javy, i jeśli opcja JIT jest aktywna, to przekształca ona kod bajtowy w kod maszynowy danego procesora, który zapisuje do pliku dyskowego. Przeglądarka wykonuje wtedy kod maszynowy. W efekcie, kompilator JIT traktuje kod bajtowy jako język źródłowy, który kompiluje do postaci programu w języku maszynowym lokalnej maszyny. Ponieważ w kodzie bajtowym nie było w trakcie kompilacji do kodu maszynowego danego procesora żadnych zmian, więc w rezultacie program ciągle jest bezpieczny i niezależny od sprzętu. Kompilacja JIT powoduje, że program napisany w Javie pracuje kilka razy szybciej niż wykonywany przez najlepszy interpreter kodu bajtowego.

Stosowanie wskaźników w C pozwala generować kod zwarty i szybki, jednak w dobie dzisiejszego "rozproszenia" zasobów i zatarcia się granicy między pamięcią operacyjną a zewnętrzną dyskową staje się to zbędne. Jest nawet niepożądane, by program wiedział, jakiego rodzaju pamięć przydziela mu system. Niezawodne systemy operacyjne nie mogą pozostawiać gospodarki zasobami maszyny do dyspozycji procesu. To system powinien mieć kontrolę nad procesem, nie odwrotnie.

Java ma tylko jeden model pamięci kompilowanego programu, stosujący referencje (nie skrępowane ograniczeniami jakie niesie segmentacja pamięci). Jest to odmienna organizacja modelu pamięci niż w C, gdzie mamy kilka modeli pamięci, o różnym stopniu ingerencji w pamięć komputera (ściślej procesora). Chroni to programistów przed możliwością popełnienia pomyłki, zaakceptowanej prze kompilator jako świadome działanie (np. przekształcenie zmiennej typu char w zmienną typu wskaźnik).