JVM başlangıçta sadece Java'yı desteklemek için tasarlandı. Ancak, zamanla, Java platformunda Scala, Kotlin ve Groovy gibi birçok dil kabul edildi. Tüm bu diller toplu olarak JVM dilleri olarak bilinir.
Bu yazıda, JVM, nasıl çalıştığı ve yapıldığı çeşitli bileşenler hakkında daha fazla bilgi edineceğiz.
JVM'ye geçmeden önce, Sanal Makine (VM) kavramına bakalım.
Sanal makine, fiziksel bir bilgisayarın sanal bir temsilidir. Sanal makineye konuk makine diyebiliriz ve üzerinde çalıştığı fiziksel bilgisayar ana makinedir.
Tek bir fiziksel makine, her biri kendi işletim sistemi ve uygulamalarına sahip birden çok sanal makineyi çalıştırabilir. Bu sanal makineler birbirinden izole edilmiştir.
C ve C ++ gibi programlama dillerinde, kod ilk olarak platforma özgü makine kodunda derlenir. Bu dillere derlenmiş diller denir.
Öte yandan, JavaScript ve Python gibi dillerde bilgisayar, talimatları derlemek zorunda kalmadan doğrudan yürütür. Bu dillere yorumlanmış diller denir.
Java, her iki tekniğin bir kombinasyonunu kullanır. Java kodu, bir sınıf dosyası oluşturmak için önce bayt kodunda derlenir. Bu sınıf dosyası daha sonra temel platform için Java Sanal Makinesi tarafından yorumlanır. Aynı sınıf dosyası, herhangi bir platformda ve işletim sisteminde çalışan herhangi bir JVM sürümünde yürütülebilir.
Sanal makinelere benzer şekilde, JVM bir ana makinede yalıtılmış bir alan oluşturur. Bu alan, makinenin platformundan veya işletim sisteminden bağımsız olarak Java programlarını çalıştırmak için kullanılabilir.
JVM, üç farklı bileşenden oluşur:
Her birine daha ayrıntılı bir şekilde bakalım.
Bir .java kaynak dosyasını derlediğinizde, .class dosyası olarak bayt koduna dönüştürülür. Bu sınıfı programınızda kullanmaya çalıştığınızda, sınıf yükleyici onu ana belleğe yükler.
Belleğe yüklenecek ilk sınıf, genellikle main () yöntemini içeren sınıftır.
Sınıf yükleme işleminin üç aşaması vardır:
yükleme, bağlama ve başlatma.
Yükleme, belirli bir ada sahip bir sınıfın veya arabirimin ikili gösterimini (bayt kodu) almayı ve oradan orijinal sınıf veya arabirimi oluşturmayı içerir.
Java'da kullanılabilen üç yerleşik sınıf yükleyici vardır:
JVM, sınıfı belleğe yüklemek için ClassLoader.loadClass () yöntemini kullanır. Sınıfı tam nitelikli bir ada göre yüklemeye çalışır.
Bir üst sınıf yükleyici bir sınıf bulamazsa, çalışmayı bir alt sınıf yükleyiciye devreder. Son alt sınıf yükleyici de sınıfı yükleyemezse, NoClassDefFoundError veya ClassNotFoundException atar.
Bir sınıf belleğe yüklendikten sonra bağlanma sürecine girer. Bir sınıfı veya arayüzü bağlamak, programın farklı unsurlarını ve bağımlılıklarını bir araya getirmeyi içerir.
Bağlama aşağıdaki adımları içerir:
Verification: (Doğrulama) Bu aşama, .class dosyasının yapısal doğruluğunu bir dizi kısıtlama veya kurala göre kontrol ederek kontrol eder. Doğrulama herhangi bir nedenle başarısız olursa, VerifyException alırız.
Örneğin, kod Java 11 kullanılarak oluşturulmuşsa ancak Java 8'in kurulu olduğu bir sistemde çalıştırılıyorsa, doğrulama aşaması başarısız olur.
Preparation (Hazırlık) Bu aşamada JVM, bir sınıfın veya arayüzün statik alanları için bellek ayırır ve bunları varsayılan değerlerle başlatır.
Örneğin, sınıfınızda aşağıdaki değişkeni bildirdiğinizi varsayalım:
private static final boolean enabled = true;
Hazırlık aşamasında, JVM, etkinleştirilen değişken için bellek ayırır ve değerini, yanlış olan bir boole için varsayılan değere ayarlar.
Resolution: (Çözüm) Bu aşamada, sembolik referanslar, çalışma zamanı sabit havuzunda bulunan doğrudan referanslarla değiştirilir.
Örneğin, diğer sınıflara veya diğer sınıflarda bulunan sabit değişkenlere referanslarınız varsa, bunlar bu aşamada çözülür ve gerçek referanslarıyla değiştirilir.
Initialization: (Başlatma) Başlatma, sınıfın veya arabirimin (<clinit> olarak bilinir) başlatma yönteminin yürütülmesini içerir. Bu, sınıfın yapıcısını çağırmayı, statik bloğu yürütmeyi ve tüm statik değişkenlere değer atamayı içerebilir. Bu, sınıf yüklemesinin son aşamasıdır.
Örneğin, aşağıdaki kodu daha önce ilan ettiğimizde:
private static final boolean enabled = true;
Etkinleştirilen değişken, hazırlık aşamasında varsayılan değeri olan false değerine ayarlandı. Başlatma aşamasında, bu değişkene gerçek değeri gerçek olarak atanır.
Not: JVM, çok iş parçacıklıdır. Birden çok iş parçacığı aynı anda aynı sınıfı başlatmaya çalışıyor olabilir. Bu eşzamanlılık sorunlarına yol açabilir. Programın çok iş parçacıklı bir ortamda düzgün çalıştığından emin olmak için iş parçacığı güvenliğini ele almanız gerekir.