Masina Virtuala Java

O aplicaţie de sine stătătoare, scrisă în Java, este compilată şi rulează pe o aşa numită Maşină Virtuală Java. Acest lucru face posibil ca aplicaţiile java să poată fi rulate pe diferite platforme (Sun, MacOS, Win32, Linux) fără a fi nevoie să se recompileze aceste aplicaţii pentru fiecare dintre acestea în parte. Astfel aplicaţiile java sunt independente de platformă.

Implementarea practică a conceptului independenţei de platformă sa realizat prin folosirea unui calculator virtual pe care rulează de fapt aplicaţiile compilate java. În urma compilării fişierelor sursă java nu se va genera cod executabil, pentru o platformă anume, ci se va genera un cod intermediar numit cod de octeţi (eng. byte code). Acest cod de octeţi este asemănător cu limbajul de asamblare dar nu va putea fi rulat direct pe nici un sistem de operare.

Pentru a rula un cod executabil java este nevoie de un program special care va interpreta acest cod de octeţi şi va executa instrucţiuni specifice sistemului de operare pe care se află. Acest program care interpretează codul de octeţi se numeşte Maşina Virtuală Java. Maşina Virtuală Java reprezintă un calculator abstract. Ca şi calculatoarele reale, aceasta dispune de un set de instrucţiuni, un set de regiştri şi utilizează diferite zone de memorie.

Garbage collector

Toate obiectele create în cadrul maşinii virtuale pe parcursul rulării unui program sunt plasate în zona de memorie numită Heap. Ştergerea acestora din memorie este realizată automat de către o componentă a JVM numita Garbage Collector. Acest proces şterge din zona Heap toate obiectele care nu mai sunt referite în cadrul programului aflat în execuţie.

Mecanismul Garbage Collector de eliberare a memorie de obiecte care nu mai sun folositoare oferă două avantaje importante. În primul rând programatorul nu trebuie sa se îngrijească în mod explicit de eliberarea obiectelor nefolositoare. Datorită unor erori de implementare care duc la situaţii de supraîncărcare a memorie programatorul poate să îşi piardă multe ore pentru a găsi şi repara defectul. Un al doilea avantaj este acela că GC asigură integritatea programelor – nu permite ştergerea accidentală a unor obiecte sau zone de memorie care ar duce pierderea integrităţii programului sau a maşinii virtuale.

Încărcare suplimentară a procesorului dată de componenta GC este un dezavantaj al acestei abordări de eliberare automate a memoriei. Această problemă este rezolvată într-o măsură destul de mare prin dezvoltarea unor algoritmi performanţi implementaţi la nivelul GC.

Este important de reţinut faptul că, nu poate fi prezis in avans momentul în care un obiect urmează să fie eliberat din memorie. Programatorul nu trebuie să îşi bazeze arhitectura programului plecând de la anumite presupuneri asupra momentului în care un anumit obiect va fi eliberat din memorie.

IMPORTANT: Deşi mecanismul GC asigură eliberarea memorie de obiectele care nu mai sunt referite, există pericolul ca un program prost gândit şi implementat să aibă probleme de alocare a memorie, şi să se ajungă la situaţia de depăşire a memorie – fapt care duce la întreruperea programului. Acest lucru se poate întâmpla deoarece GC şterge din zona Heap doar acele obiecte care nu sunt referite de către nici o variabila.

Deşi nu se poate şti în avans exact momentul în care un obiect este eliberat din memorie, obiectele care urmează să fie şterse sunt anunţate prin apelarea metodei finalize(). Metoda finalize() se regăseşte în cadrul oricărui obiect java (fiind moştenită din cadrul clasei de bază Object) şi este apelată de către GC în momentul în care obiectul urmează să fie şters.

public class GarbageCollectorTest {
            static int removedObjects;
            public static class Flower{
                        String name;
                        Flower(String name){
                                    this.name = name;
                        }                      
                        public void finalize(){
                                    removedObjects++;
                                    System.err.println("The flower "+name+" is removed. Number of removed flowers is "+removedObjects);
                        }
            }
            public static void main(String[] args) {
                        Flower myF = null;
                        for(int i=0;i<10000;i++)
                                    myF = new Flower(" Flower "+i);
            }
}

În listingul anterior este prezentat un program care demonstrează faptul că la eliberarea fiecărui obiect din memorie este apelată metoda finalize() a acestuia.

IMPORTANT: Intrarea în acţiune a GC şi eliberarea memoriei de obiecte (deci implicit apelarea metodei finalize()) nu este garantată de către maşina virtuală java. Ca urmare a acestui fapt, toate operaţiile de eliberarea de resurse care trebuiesc realizate în cadrul unei aplicaţii (de exemplu închiderea unor conexiuni de reţea, unor fişiere, închiderea unor conexiuni la baze de date, etc.) trebuie să fie realizate de programator în mod manual prin construirea unor metode care sunt apelate în mod explicit la momentul potrivit.