Java'nın Sanal Makinesi ve CLR


140

MSIL ve Java bayt kodu arasındaki farklar adlı soruya bir tür takip olarak ? , Java Sanal Makinesi'nin çalışma biçimine (.NET Framework Ortak Dil Çalışma Zamanı (CLR) çalışıyor?

Ayrıca, .NET çerçevesi CLR "sanal makine" veya sanal makinenin nitelikleri yok mu?


Peki, beğen ve beğenirseniz, soruyu VM ile doğrudan VM'nin analog olan CLR (Ortak Dil Çalışma Zamanı) arasındaki fark olarak yeniden yazmalısınız.
cletus

Yanıtlar:


278

Her iki uygulama arasında birçok benzerlik var (ve bence: evet, her ikisi de "sanal makineler").

Birincisi, ikisi de yığın tabanlı VM'ler, x86 veya PowerPC gibi modern bir CPU'da görmeye alışık olduğumuz gibi "kayıt" kavramı yok. Tüm ifadelerin ((1 + 1) / 2) değerlendirilmesi, işlenenlerin "yığın" üzerine itilmesi ve daha sonra bir talimatın (ekleme, bölme, vb.) Bu işlenenleri tüketmesi gerektiğinde bu işlenenleri yığından atmak suretiyle gerçekleştirilir. Her talimat sonuçlarını yığına geri iter.

Sanal bir makine uygulamak için uygun bir yoldur, çünkü dünyadaki hemen hemen her CPU'nun bir yığını vardır, ancak kayıt sayısı genellikle farklıdır (ve bazı kayıtlar özel amaçlıdır ve her talimat, işlenenlerini farklı kayıtlarda vb. ).

Yani, soyut bir makineyi modelleyecekseniz, tamamen yığın tabanlı bir model gitmek için oldukça iyi bir yoldur.

Tabii ki, gerçek makineler bu şekilde çalışmaz. Bu nedenle JIT derleyicisi, bayt kodu işlemlerinin "kayıt" işleminden, esasen gerçek CPU kayıtlarını mümkün olduğunda işlenenleri ve sonuçları içerecek şekilde programlamaktan sorumludur.

Bence bu CLR ve JVM arasındaki en büyük ortak noktalardan biri.

Farklılıklara gelince ...

İki uygulama arasındaki ilginç bir fark, CLR'nin genel türler oluşturmak ve daha sonra bu türlere parametrik uzmanlıklar uygulamak için talimatlar içermesidir. Bu nedenle, çalışma zamanında, CLR bir List <int> öğesini bir List <String> öğesinden tamamen farklı bir tür olarak kabul eder.

Kapakların altında, tüm başvuru türü uzmanlıkları için aynı MSIL'i kullanır (bu nedenle bir Liste <String>, API sınırlarında farklı tür yayınları olan bir Liste <Object> ile aynı uygulamayı kullanır), ancak her değer türü kullanır kendi benzersiz uygulaması (Liste <int> Liste <double> 'den tamamen farklı bir kod üretir).

Java'da genel türler tamamen derleyici bir numaradır. JVM'nin hangi sınıfların tür bağımsız değişkenleri olduğu hakkında hiçbir fikri yoktur ve çalışma zamanında parametrik uzmanlıklar gerçekleştiremez.

Pratik açıdan bakıldığında, genel türlerde Java yöntemlerini aşırı yükleyemeyeceğiniz anlamına gelir. Aynı ada sahip iki farklı yönteme sahip olamazsınız, yalnızca bir Liste <Dizleme> veya bir Liste <Tarih> kabul edip etmediklerine göre farklılık gösterir. Tabii ki, CLR parametrik türleri bildiğinden, genel tip uzmanlıklarına aşırı yüklenmiş sorun giderme yöntemleri yoktur.

Günlük bazda, CLR ve JVM arasında en çok fark ettiğim fark bu.

Diğer önemli farklılıklar şunları içerir:

  • CLR'nin kapanışları vardır (C # delegeleri olarak uygulanır). JVM, yalnızca Java 8'den beri kapanmaları destekler.

  • CLR'de (C # 'verim' anahtar kelimesiyle uygulanan) couteinler bulunur. JVM bunu yapmaz.

  • CLR, kullanıcı kodunun yeni değer türleri (yapılar) tanımlamasına izin verirken, JVM sabit bir değer türleri koleksiyonu (bayt, kısa, int, uzun, kayan nokta, çift, karakter, boole) sağlar ve yalnızca kullanıcıların yeni referans tanımlamasına izin verir. türleri (sınıfları).

  • CLR, işaretçilerin bildirilmesi ve işlenmesi için destek sağlar. Bu özellikle ilginçtir çünkü hem JVM hem de CLR, bellek yönetimi stratejisi olarak katı nesil sıkıştırma çöp toplayıcı uygulamaları kullanmaktadır. Sıradan koşullar altında, sıkı bir sıkıştırma GC'sinin işaretçilerle gerçekten zor bir zamanı vardır, çünkü bir değeri bir bellek konumundan diğerine taşıdığınızda, tüm işaretçiler (ve işaretçilerden işaretleyicilere) geçersiz olur. Ancak CLR, geliştiricilerin CLR'nin belirli işaretçileri hareket ettirmesine izin verilmediği bir kod bloğu bildirebilmeleri için bir "sabitleme" mekanizması sağlar. Çok uygun.

  • JVM'deki en büyük kod birimi ya 'korumalı' anahtar kelime ile kanıtlandığı gibi bir 'paket' ya da sınıf yolunda bir kavanoz belirleyip bir klasör gibi davranarak kanıtlanabilir bir JAR'dır (yani Java ARchive). kod. CLR'de, sınıflar 'derlemeler' halinde toplanır ve CLR, derlemeler hakkında mantık yürütmek ve işlemek için mantık sağlar (bunlar "AppDomains" e yüklenir, bellek ayırma ve kod yürütme için alt uygulama düzeyinde sanal alanlar sağlar).

  • CLR bayt kodu biçimi (MSIL talimatları ve meta verilerden oluşur) JVM'den daha az komut türüne sahiptir. JVM'de her benzersiz işlemin (iki int değeri ekleyin, iki float değeri ekleyin, vb.) Kendi benzersiz talimatı vardır. CLR'de, tüm MSIL talimatları polimorfiktir (iki değer ekleyin) ve JIT derleyicisi, işlenen türlerini belirlemek ve uygun makine kodu oluşturmaktan sorumludur. Yine de tercih edilen stratejinin hangisi olduğunu bilmiyorum. Her ikisinin de ödünleri var. JVM için HotSpot JIT derleyicisi daha basit bir kod oluşturma mekanizması kullanabilir (talimatlarda zaten kodlandıkları için işlenen türlerini belirlemesine gerek yoktur), ancak bu daha karmaşık bir bayt kodu formatına ihtiyaç duyduğu anlamına gelir, daha fazla talimat türü ile.

Yaklaşık on yıldır Java kullanıyorum (ve JVM'ye hayranım).

Fakat bence CLR şimdi neredeyse her şekilde üstün bir uygulama.


73
Kapaklar ve üreteçler bir dil düzeyinde uygulanır ve sadece CLR düzeyinde sınıflar olarak temsil edilir.
Curt Hagenlocher

2
Yığını nasıl ele aldıkları arasındaki farklar ne olacak? JRM, yığın belleğini az çok tamamen yönetirken CLR, OS / host proc'a daha bağımlıdır.
Kelly

6
Önemli bir fark, tam zamanında derleme (CLR) ile (Oracle / Sun) JVM'de uyarlanabilir optimizasyon arasındaki kontrasttır.
Edwin Dalorzo

1
Java'nın yerel değişken yuvaları, kayıtlara çok benzer. Ancak JIT yerel yuvaları ve yığını gerçek kayıtlara dönüştürdüğü için her şey yolunda.
Antimon

1
@kuhajeyan, çünkü CLR tanıtıldığında, JVM 10 yaşındaydı. BT'de uzun zaman oldu. 1993 yılında JVM geldiğinde ciddi bir rakip yoktu, CLR (2003) için endüstride güçlü dayanaklara sahip olgun ve sağlam bir JVM vardı.
Basit Fellow

25

İlk sorunuz JVM'yi .NET Framework ile karşılaştırmak - aslında bunun yerine CLR ile karşılaştırmak istediğinizi varsayalım. Eğer öyleyse, bu konuda küçük bir kitap yazabilirsiniz ( EDIT: Benji zaten var :-) gibi görünüyor

Önemli bir fark, CLR'nin JVM'den farklı olarak dilden bağımsız bir mimari olarak tasarlanmasıdır.

Bir başka önemli fark, CLR'nin yerel kodla yüksek düzeyde birlikte çalışabilirlik sağlamak için özel olarak tasarlanmış olmasıdır. Bu, yerel belleğe erişildiğinde ve değiştirildiğinde CLR'nin güvenilirliği ve güvenliği yönetmesi ve ayrıca CLR tabanlı veri yapıları ile yerel veri yapıları arasındaki uyumlamayı yönetmesi gerektiği anlamına gelir .

İkinci sorunuza cevap vermek için, “sanal makine” terimi, aynı makineyi gerçekleştirmek için temeldeki makinenin bir yazılım / donanım öykünmesi anlamına gelen donanım dünyasından daha eski bir terimdir (örneğin, IBM'in 1960'larda 360'ı sanallaştırması). VMWare tarafından yapılan şeyler.

CLR'ye genellikle "yürütme motoru" denir. Bu bağlamda, bu bir IL 86'nın x86 üstüne bir uygulamasıdır. CLV'nin polimorfik bayt kodları ile JVM'nin yazılan bayt kodları arasında önemli bir fark olduğunu iddia etmenize rağmen, JVM'nin yaptığı da budur.

Yani ikinci sorunuzun bilgiçlikle cevabı "hayır" dır. Ama gerçekten bu iki terimi nasıl tanımladığınıza bağlı.

DÜZENLEME: JVM ve CLR arasındaki bir fark daha, JVM'nin (sürüm 6), tahsis edilen belleği, çalışabildiği yerde bile işletim sistemine geri bırakmak konusunda çok isteksiz olmasıdır.

Örneğin, bir JVM işleminin başladığını ve başlangıçta işletim sisteminden 25 MB bellek ayırdığını varsayalım. Uygulama kodu daha sonra ek 50 MB gerektiren ayırma girişiminde bulunur. JVM, işletim sisteminden 50 MB ek bellek ayıracaktır. Uygulama kodu bu belleği kullanmayı bıraktığında, çöp toplanır ve JVM yığın boyutu azalır. Ancak, JVM yalnızca belirli çok özel koşullar altında ayrılan işletim sistemi belleğini boşaltacaktır . Aksi takdirde, işlem ömrü boyunca bu bellek ayrılmış olarak kalacaktır.

Öte yandan CLR, artık gerekmediyse tahsis edilen belleği işletim sistemine geri bırakır. Yukarıdaki örnekte, yığın azaldığında CLR hafızayı serbest bırakırdı.


2
JVM'nin boş bellek ayırmayacağı doğru değildir. Kanıt için bu soruya verdiğim cevaba bakın: stackoverflow.com/questions/366658/…
Michael Borgwardt

JVM'nin belleği Windows'a geri döndürdüğünü gördüm.
Steve Kuo

Cevabımı JVM 6'nın Ran'ın ve Michael'ın cevaplarına bağlantılarla hafızayı serbest bırakmak konusunda çok isteksiz olduğunu söylemek için değiştirdim. JVM 5 ile bu davranışı hiç görmedim, bu yüzden bu sürüm daha da isteksizdi.
HTTP 410

CLR ebeveyn sürecine güvenirken JVM'nin yığını nasıl yönettiğini ele alabilir misiniz? Kullandığım özel örnek, varsayılan CLR ortamı olmasa da JVM'nin maksimum yığın boyutu için çalışma zamanı değişkenlerine sahip olmasıdır. IIS altında barındırılan bir CLR uygulaması, IIS'yi belleği sınırlayacak şekilde yapılandırabilir, bu da IIS'yi sanal makine tanımına dahil etmek anlamına gelir.
Kelly

@Steve Kuo, evet ben de gördüm. genellikle 17:00 - 18:00 arasında.
Basit Fellow

11

CLR ve JVM'nin ikisi de sanal makinedir.

.NET Framework ve Java Runtime Environment ilgili VM'lerin ve kitaplıklarının paketlenmesidir. Kütüphaneler olmadan VM'ler işe yaramaz.


11

Farklı akademik ve özel kaynaklardan farklılıklar hakkında daha fazla ayrıntı bulunabilir. Bir kere iyi bir örnek CLR Tasarım Seçimleridir .

Bazı özel örnekler şunları içerir:

  • CLR bir polimorfik işlenen kullandığı için "iki int ekle" gibi bazı düşük seviyeli rakipler yazılır. (yani fadd / iadd / ladd vs sadece ekle)
  • Şu anda, JVM daha agresif çalışma zamanı profili oluşturma ve optimizasyonu (örn. Hotspot) yapmaktadır. CLR şu anda JIT optimizasyonlarını yapıyor, ancak çalışma zamanı optimizasyonunu yapmıyor (yani kodu çalıştırırken değiştirin).
  • CLR sanal yöntemleri satmaz, JVM yapar ...
  • CLR'de sadece "ilkellerin" ötesinde değer türleri için destek.

-11

Bu sanal bir makine değil, .net çerçevesi derlemeleri ilk çalıştırma sırasında yerel ikili dosyaya derler:

Hesaplamada, dinamik çeviri olarak da bilinen tam zamanında derleme (JIT), bir bilgisayar programının çalışma zamanının performansını artırmak için bir tekniktir. JIT, çalışma zamanı ortamlarında önceki iki fikre dayanır: bayt kodu derlemesi ve dinamik derleme. Yerel olarak çalıştırmadan önce kodu çalışma zamanında dönüştürür, örneğin bayt kodu yerel makine koduna. Tercümanlara göre performans artışı, kod bloklarının çevrilmesi sonuçlarını önbelleğe almaktan ve her satır veya işlenenle her karşılaştığında yeniden değerlendirmekten kaynaklanır (Yorumlanmış dil). Ayrıca, kodun geliştirme zamanında statik olarak derlenmesine göre avantajları vardır, çünkü avantajlı olduğu tespit edilirse ve güvenlik garantilerini uygulayabilir.

Microsoft'un .NET Framework, Java uygulamalarının çoğu ve son olarak Actionscript 3 gibi çeşitli modern çalışma ortamı, yüksek hızlı kod yürütme için JIT derlemesine dayanır.

Kaynak: http://en.wikipedia.org/wiki/Just-in-time_compilation

.NET çerçevesi eklemek, tıpkı Java gibi bir sanal makine içerir.


10
Sanal makinenin performans optimizasyonu için JIT'i kullanması, artık sanal makine olmadığı anlamına gelmez. Programcı sanal makineyi derlediğinde, uygulamayı ancak uygun görmesi için uygulamaya bırakarak derler
Allain Lalonde
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.