Tuple Logo
java-virtual-machine-jvm

SHARE

Java Virtual Machine (JVM)

Wat is de Java Virtual Machine?

De Java Virtual Machine (JVM) is een virtuele omgeving die Java-programma’s uitvoert door gecompileerde bytecode te interpreteren of te compileren naar machinecode. Het vormt de kern van het Java-platform en maakt het mogelijk om Java-toepassingen platformonafhankelijk, veilig en efficiënt uit te voeren.

De JVM fungeert als een softwarematige abstractie-laag tussen de gecompileerde Java-code en het onderliggende besturingssysteem. In plaats van Java-code direct te vertalen naar de machinecode van een specifiek apparaat, wordt de code eerst omgezet naar bytecode. Deze bytecode is een universeel formaat dat door elke JVM kan worden gelezen en uitgevoerd, ongeacht het platform waarop deze draait.

Dankzij deze aanpak kunnen Java-programma’s probleemloos draaien op verschillende besturingssystemen, zolang daar een JVM beschikbaar is. Dit maakt Java bijzonder krachtig voor ontwikkelaars die applicaties willen bouwen die op meerdere apparaten en systemen werken zonder de code te herschrijven.

Belangrijk om te weten: de JVM is geen programmeertaal, maar een specificatie. Dit betekent dat er meerdere implementaties bestaan, zoals Oracle HotSpot en OpenJ9, zolang ze voldoen aan de regels die zijn vastgelegd in de officiële specificatie van Oracle.

Rol in de Java-architectuur

De JVM is één van de drie kernonderdelen van het Java-platform:

Zonder de JVM zou Java zijn belangrijkste voordeel verliezen: het vermogen om platformonafhankelijke applicaties te bouwen.

Waarom is de JVM belangrijk?

De Java Virtual Machine is om meerdere redenen een essentieel onderdeel van het Java-ecosysteem. Het is niet alleen een runtime-omgeving, maar ook een fundering voor prestaties, veiligheid en flexibiliteit in softwareontwikkeling.

Platformonafhankelijkheid

De JVM maakt het mogelijk om applicaties één keer te schrijven en overal uit te voeren. Dit principe – “write once, run anywhere” – is een van de belangrijkste troeven van Java. Doordat de Java-compiler de code omzet naar bytecode en deze door de JVM wordt geïnterpreteerd of gecompileerd, maakt het niet uit op welk besturingssysteem of apparaat de applicatie draait. Zolang een geschikte JVM aanwezig is, werkt de software.

Ondersteuning voor meerdere talen

Hoewel de JVM oorspronkelijk voor Java is ontworpen, ondersteunt het tegenwoordig ook andere programmeertalen. Denk aan:

Deze talen worden eveneens gecompileerd naar bytecode en kunnen daardoor gebruikmaken van de bestaande Java-bibliotheken en -tools. Dit maakt de JVM tot een veelzijdig platform voor moderne softwareontwikkeling.

Beveiliging en sandboxing

De JVM bevat ingebouwde beveiligingsmaatregelen die beschermen tegen onveilige of schadelijke code. Denk aan:

Deze functies maken de JVM geschikt voor omgevingen waar betrouwbaarheid en veiligheid cruciaal zijn, zoals bij webapplicaties of mobiele apps.

Hoe werkt de JVM?

De werking van de Java Virtual Machine bestaat uit verschillende stappen en componenten die samenwerken om Java-programma’s correct en efficiënt uit te voeren. Het proces begint bij het compileren van de broncode en eindigt bij het uitvoeren van de instructies in de runtime-omgeving.

Compileerproces: van broncode naar bytecode

Wanneer een Java-programma wordt geschreven, wordt de broncode opgeslagen in .java-bestanden. Deze bestanden worden gecompileerd door de Java Compiler (javac) tot .class-bestanden met bytecode. Bytecode is geen machinecode, maar een compact en gestandaardiseerd instructieformaat dat bedoeld is voor de JVM.

Rol van de class loader

De JVM bevat een class loader subsystem dat verantwoordelijk is voor het laden van de gecompileerde klassen op het moment dat ze nodig zijn. Er zijn meerdere types class loaders, waaronder:

De class loader voorkomt dubbele laadtaken en zorgt ervoor dat klassen in de juiste volgorde worden geladen.

Bytecode verificatie

Zodra een klasse is geladen, voert de JVM een verificatiestap uit. De bytecode wordt gecontroleerd op geldigheid, consistentie en veiligheid. Dit voorkomt dat corrupte of kwaadaardige code schade aanricht of crasht. De verifier checkt onder andere:

Class file structuur

Een .class-bestand bevat meer dan alleen instructies. De structuur bestaat uit:

Deze structuur stelt de JVM in staat om de bytecode correct te interpreteren, methoden aan te roepen, objecten aan te maken en het programma uit te voeren zoals bedoeld.

Belangrijke componenten van de JVM

De JVM bestaat uit verschillende subsystemen die elk een specifieke rol spelen tijdens de uitvoering van een Java-programma. Samen zorgen ze voor efficiënt geheugenbeheer, veilige uitvoering en hoge prestaties.

Class loader subsystem

Het class loader subsystem is verantwoordelijk voor het dynamisch laden van klassen wanneer deze nodig zijn. Dit gebeurt niet vooraf, maar tijdens de uitvoering van het programma. De class loader bepaalt hoe en waar klassen worden gevonden, geladen en geïsoleerd. Dit maakt onder andere plug-in-architecturen en modulaire applicaties mogelijk.

JVM memory model

De JVM beheert het geheugen op een gestructureerde manier. De belangrijkste geheugengebieden zijn:

Execution engine

De execution engine voert de bytecode uit. Deze bestaat uit:

Just-In-Time (JIT) compiler

De JIT-compiler analyseert tijdens het uitvoeren welke methodes vaak worden gebruikt en compileert deze naar efficiënte machinecode. Zo kan de JVM de prestaties van het programma sterk verbeteren zonder dat de ontwikkelaar iets hoeft aan te passen. Deze optimalisaties vinden plaats tijdens runtime.

Garbage collection

De JVM voert automatisch garbage collection uit om geheugen vrij te maken dat niet meer wordt gebruikt. Het bepaalt welke objecten niet langer bereikbaar zijn en verwijdert ze uit de heap. Afhankelijk van de gekozen JVM-implementatie en instellingen zijn er verschillende algoritmes beschikbaar, zoals:

Elke variant heeft zijn eigen voordelen, afhankelijk van de applicatie en systeemvereisten.

Java Native Interface (JNI)

De JNI maakt het mogelijk om Java-code te combineren met native code, bijvoorbeeld geschreven in C of C++. Dit is handig voor prestaties of wanneer een systeemfunctie nodig is die niet via Java beschikbaar is. JNI brengt wel extra complexiteit en veiligheidsrisico’s met zich mee.

Native method library’s

De JVM heeft toegang tot native library’s, bijvoorbeeld voor netwerkfunctionaliteit of systeeminteractie. Deze library’s worden gekoppeld via JNI en uitgevoerd buiten de Java-runtime om.

Multithreading en synchronisatie

De Java Virtual Machine ondersteunt standaard multithreading, waarmee meerdere taken tegelijkertijd uitgevoerd kunnen worden binnen één applicatie. Dit is essentieel voor moderne toepassingen die responsief moeten blijven en optimaal gebruik willen maken van meerdere processorkernen.

Hoe de JVM threads beheert

Elke thread in Java wordt gemanaged door de JVM en krijgt een eigen stackruimte. Wanneer een programma wordt gestart, maakt de JVM automatisch een main thread aan. Daarna kunnen via het Thread-object of via Runnable extra threads worden aangemaakt.

De JVM verdeelt de uitvoering van deze threads op basis van het onderliggende besturingssysteem, maar zorgt ook intern voor:

Synchronisatie van methoden en objecten

Bij multithreading kunnen meerdere threads tegelijk toegang proberen te krijgen tot gedeelde bronnen, zoals variabelen of objecten. Om race conditions of data-corruptie te voorkomen, biedt de JVM verschillende synchronisatie-mechanismen:

De JVM garandeert dat alle synchronisatie-regels correct worden toegepast volgens het Java Memory Model, dat bepaalt hoe en wanneer wijzigingen aan variabelen zichtbaar zijn voor andere threads.

Beveiligingsfuncties van de JVM

Een belangrijk voordeel van de Java Virtual Machine is de ingebouwde beveiliging. De JVM is ontworpen om kwaadaardige of foutieve code te isoleren en de gebruiker en het systeem te beschermen. Deze beveiligingslaag maakt Java geschikt voor toepassingen waar veiligheid essentieel is, zoals webapplicaties, mobiele apps en embedded systemen.

Bytecode verifier

Zodra een .class-bestand wordt geladen, controleert de bytecode verifier of de instructies geldig zijn. Deze controle voorkomt dat code:

Als de bytecode niet voldoet aan de verwachte structuur en regels, wordt de uitvoering direct gestopt.

ClassLoader-isolatie

De JVM maakt gebruik van meerdere class loaders, die klassen kunnen scheiden op basis van herkomst. Dit voorkomt dat code uit onbetrouwbare bronnen toegang krijgt tot interne onderdelen van het programma. Zo kunnen bibliotheken van derden veilig worden gebruikt, zonder dat ze systeemcomponenten beïnvloeden.

Elke class loader heeft zijn eigen namespace, wat betekent dat dezelfde klasse meerdere keren geladen kan worden, elk in zijn eigen context. Dit biedt flexibiliteit én extra veiligheid.

Security Manager

De Security Manager is een optionele component die regels definieert over wat een bepaalde code wel of niet mag doen. Denk aan:

Met behulp van een policy file kun je fijnmazig bepalen welke rechten een stuk code krijgt. Hierdoor kan je bijvoorbeeld applets of plug-ins laten draaien in een gecontroleerde omgeving.

JVM en andere programmeertalen

Hoewel de Java Virtual Machine oorspronkelijk is ontwikkeld voor Java, ondersteunt het platform tegenwoordig een breed scala aan andere programmeertalen. Deze talen zijn speciaal ontworpen of aangepast om te kunnen draaien op de JVM en maken gebruik van dezelfde infrastructuur, zoals geheugenbeheer, garbage collection en beveiliging.

Ondersteuning voor meerdere talen

Talen die bytecode genereren en dus gebruik kunnen maken van de JVM, worden ook wel JVM-talen genoemd. Enkele populaire voorbeelden zijn:

Dankzij deze talen kunnen ontwikkelaars gebruikmaken van moderne programmeerconcepten, zonder de stabiliteit en volwassenheid van het JVM-ecosysteem op te geven.

Verschil tussen JVM-talen en JVM-implementaties

Het is belangrijk om onderscheid te maken tussen JVM-talen en JVM-implementaties:

Alle implementaties volgen de officiële specificatie, maar verschillen in prestaties, geheugenverbruik en optimalisaties. Zo biedt GraalVM bijvoorbeeld ondersteuning voor polyglot-programmering (meerdere talen tegelijk) en ahead-of-time compilatie.

Door deze veelzijdigheid is de JVM niet alleen relevant voor Java-ontwikkelaars, maar ook voor iedereen die moderne applicaties wil bouwen in een stabiel en flexibel ecosysteem.

JVM aanpasbaar gedrag en optimalisaties

De JVM is meer dan alleen een uitvoeringsomgeving. Het biedt een breed scala aan instellingen en optimalisaties die ontwikkelaars en systeembeheerders kunnen gebruiken om prestaties te verbeteren, geheugengebruik te beheren en gedrag aan te passen aan specifieke situaties.

Command-line opties

Via command-line opties kun je het gedrag van de JVM tijdens het opstarten beïnvloeden. Enkele veelgebruikte voorbeelden:

Deze instellingen helpen bij het afstemmen van JVM-prestaties op de behoeften van een specifieke applicatie of omgeving.

Verschillende garbage collectors

De JVM ondersteunt meerdere algoritmen voor garbage collection. Elke variant heeft zijn eigen kenmerken en is geschikt voor specifieke toepassingen:

Garbage CollectorKenmerkGebruik
Serial GCEenvoudig, single-threadedKleine applicaties of omgevingen met weinig geheugen
Parallel GCMeerdere threads, throughput gerichtApplicaties die veel geheugen nodig hebben
G1 GCVerdeling in regio’s, lage pauzesAlgemene productieomgevingen
ZGCZeer lage latency, schaalbaarReal-time of grote datasystemen

De juiste keuze heeft direct invloed op prestaties en responstijd van de applicatie.

Client vs. server JVM

De JVM kent twee varianten die elk zijn geoptimaliseerd voor verschillende situaties:

De juiste versie wordt vaak automatisch geselecteerd, maar kan ook handmatig worden ingesteld met -client of -server.

JVM in embedded en real-time toepassingen

De flexibiliteit van de Java Virtual Machine maakt het mogelijk om deze niet alleen in desktop- en serveromgevingen te gebruiken, maar ook in embedded systemen en real-time toepassingen. Hiervoor bestaan speciale varianten en aanpassingen van de JVM die inspelen op de beperkingen en eisen van deze omgevingen.

Gebruik in embedded systemen

In embedded systemen – zoals routers, printers, industriële apparaten of IoT-toestellen – zijn resources zoals geheugen en rekenkracht vaak beperkt. Toch kan de JVM hier worden ingezet, dankzij lichtgewicht implementaties zoals:

Deze implementaties zijn geoptimaliseerd voor een klein geheugenverbruik en een laag stroomverbruik, met behoud van de voordelen van Java, zoals portabiliteit en veiligheid. Ze bieden vaak een subset van de volledige Java SE-functionaliteit.

Voordelen van de JVM in embedded omgevingen:

Real-time JVM-varianten

Voor toepassingen waar strikte tijdsbeperkingen gelden – zoals in medische apparatuur, defensiesystemen of industriële besturing – zijn standaard JVM’s vaak niet geschikt vanwege onvoorspelbare garbage collection-pauzes of scheduling-gedrag.

Daarom zijn er real-time JVM’s, zoals:

Deze JVM’s bieden:

Hoewel deze varianten minder gangbaar zijn dan de standaard JVM’s, tonen ze aan hoe breed inzetbaar het concept van de Java Virtual Machine is – zelfs buiten traditionele softwareomgevingen.

Beschikbaarheid en implementaties

De Java Virtual Machine is wereldwijd beschikbaar op vrijwel elk besturingssysteem en platform. Omdat het een open specificatie is, bestaan er meerdere implementaties die allemaal dezelfde basisprincipes volgen, maar verschillen in prestaties, licentie, doel en extra functionaliteit.

Populaire JVM-implementaties

Er zijn meerdere bekende implementaties van de JVM. Hieronder een overzicht van de meest gebruikte:

ImplementatieBeschrijving
HotSpot (Oracle/OpenJDK)De standaard en meest gebruikte JVM. Ondersteunt zowel client- als servermodi en bevat de HotSpot JIT-compiler. Wordt geleverd bij de meeste Java-distributies.
GraalVMEen geavanceerde JVM met ondersteuning voor meerdere talen (Java, JavaScript, Python, Ruby) en ahead-of-time compilatie voor extreem snelle opstarttijden. Zeer geschikt voor microservices.
Eclipse OpenJ9Een lichtgewicht, prestatiegerichte JVM ontwikkeld door IBM. Biedt sneller geheugenbeheer en kortere laadtijden dan HotSpot.
Zulu / Amazon Corretto / Liberica JDKOpenJDK-builds met commerciële ondersteuning. Volledig compatibel met de standaard JVM-specificatie.

Alle bovengenoemde varianten volgen de Java Virtual Machine Specification, waardoor ze dezelfde bytecode kunnen draaien. De keuze hangt meestal af van prestatievereisten, licentievoorkeuren en extra functionaliteiten zoals monitoring of cloudoptimalisaties.

Beschikbaarheid per platform

De JVM is beschikbaar voor:

Dit maakt het mogelijk om dezelfde applicatie uit te voeren op laptops, servers, mobiele telefoons en IoT-devices zonder codewijzigingen.

De rol van de JVM in moderne software

De Java Virtual Machine is al decennialang een fundamenteel onderdeel van softwareontwikkeling. Wat begon als een oplossing voor platformonafhankelijke Java-applicaties, is uitgegroeid tot een krachtig ecosysteem dat ondersteuning biedt voor meerdere talen, moderne architecturen en uiteenlopende toepassingen.

De kracht van de JVM zit in de combinatie van:

Of je nu werkt aan een Android-app, een cloudservice of een IoT-toepassing: de JVM blijft een betrouwbare en krachtige motor onder moderne software. Met ondersteuning voor steeds meer talen en nieuwe tools zoals GraalVM, bewijst de Java Virtual Machine zich opnieuw in een snel veranderend technologisch landschap.

Veelgestelde vragen
Wat betekent JVM?

JVM staat voor Java Virtual Machine. Het is een virtuele machine die Java-bytecode uitvoert, ongeacht het onderliggende besturingssysteem.


Is JVM stackgebaseerd?

Ja, de JVM is stackgebaseerd. Elke thread krijgt zijn eigen stack waarin methoden, variabelen en returnwaarden worden beheerd tijdens de uitvoering.


Hoe werkt de Java virtuele machine?

De JVM laadt gecompileerde bytecode, verifieert deze op veiligheid, en voert de instructies uit via een interpreter of JIT-compiler. Hierbij beheert het automatisch geheugen, threads en objecten.


Wat is de taak van de Java Virtual Machine?

De JVM voert Java-programma’s uit door bytecode te interpreteren of compileren naar machinecode. Daarnaast zorgt het voor geheugenbeheer, beveiliging en platformonafhankelijkheid.


Ook interessant

Nieuwsgierig geworden?

Wij vertellen je graag meer!

Contact opnemen
Tuple Logo
Veenendaal (HQ)
De Smalle Zijde 3-05, 3903 LL Veenendaal
info@tuple.nl‭+31 318 24 01 64‬
Snel navigeren
Succesverhalen