Yeni Başlayanlar İçin Java Sanal Makine Mimarisi

JVM, Java ekosisteminin çekirdeğidir ve Java tabanlı yazılım programlarının "bir kez yaz, her yerde çalıştır" yaklaşımını izlemesini mümkün kılar. Java kodunu bir makineye yazabilir ve JVM'yi kullanarak başka bir makinede çalıştırabilirsiniz.

23 Ocak 2021, Cumartesi Serkan Yalçın 32
Paylaş: Facebookta Paylaş Twitter da paylaş

JVM


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.


Sanal Makine Nedir?


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.


Java Sanal Makinesi Nedir?

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.


Java Sanal Makine Mimarisi


JVM, üç farklı bileşenden oluşur:

  1. Class Loader (Sınıf Yükleyici)
  2. Runtime Memory/Data Area (Çalışma Zamanı Belleği / Veri Alanı)
  3. Execution Engine (Yürütme Motoru)


Her birine daha ayrıntılı bir şekilde bakalım.

Class Loader


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.

Loading

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:

  • Bootstrap Sınıf Yükleyici - Bu, kök sınıf yükleyicidir. Uzantı Sınıfı Yükleyicinin üst sınıfıdır ve java.lang, java.net, java.util, java.io vb. Gibi standart Java paketlerini yükler. Bu paketler rt.jar dosyasında ve $ JAVA_HOME / jre / lib dizininde bulunan diğer çekirdek kitaplıklarda bulunur.
  • Uzantı Sınıf Yükleyicisi - Bu, Bootstrap Sınıf Yükleyicinin alt sınıfı ve Uygulama Sınıfı Yükleyicinin üst sınıfıdır. Bu, $ JAVA_HOME / jre / lib / ext dizininde bulunan standart Java kitaplıklarının uzantılarını yükler.
  • Uygulama Sınıfı Yükleyici - Bu, Uzantı Sınıf Yükleyicinin son sınıf yükleyicisi ve alt sınıfıdır. Sınıf yolunda bulunan dosyaları yükler. Varsayılan olarak, sınıf yolu uygulamanın geçerli dizinine ayarlanır. Sınıf yolu, -classpath veya -cp komut satırı seçeneği eklenerek de değiştirilebilir.

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.

Linking (Bağlanıyor)


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.