Soru CLR bir sanal makine mi?


.Net’e atıfta bulunan bir kitap okudum Bir sanal makine olarak CLR? Herkes bunu haklı çıkarabilir mi? Bazı geliştirme platformlarında sanal makineler kavramına ihtiyacımızın sebebi nedir?

Tamamen nesne yönelimli ve .net kadar güçlü bir yerel çerçeve [sanal makine olmadan] geliştirmek mümkün değil mi?

CLR'yi sanal makine olarak anlatan kitap "Profesyonel .Net Framework 2.0".


44
2017-10-14 05:13


Menşei


Bu gerçekten bir "sanal makine" nin ne olduğuyla ilgili bir argüman. "Native" x86 komut setinin CPU tarafından yorumlanan sanal makine komut seti olarak görülebildiğini unutmayın. Yani CLR bir sanal makinenin üstünde çalışıyorsa, bunun bir sanal makine olarak kabul edilmemesi mümkün mü? - Kristopher Johnson
CLR bir "sanal makine" nin üstünde çalışmaz. CLR tam zamanında bir derleyici ve çöp toplayıcı. CLR'nin bir C kütüphanesine girmesi gerektiğinde, JNI'nin zaten yerel kod olduğu için yok olduğu anlamına gelmez, yani yapılması gereken tek şey argümanları yığının üstüne itmek ve yönteme atlamaktır. Java, bu senaryoyu yapmak için her türlü pahalı jimnastiği yapmak zorundayken, yerel koda çok yavaş bir köprü oluşturur. - hoodaticus
@hoodaticus: .NET, VMware, VirtualBox, Virtual PC, vb. içinde gayet iyi çalışıyor, bu yüzden neden VM'lerde çalışmadığına dair evrensel bir iddia yaptığınızı bilmiyorum. Ama sanırım CLR'in kendisi bir VM mi, bir tanesinin üstünde mi çalışıp çalışmadığını değil. Söylediğiniz gibi, CLR bir JIT derleyicisine ve bir çöp toplayıcısına sahiptir. Ama doğrulayıcıyı kaçırdın. Ve güvenlik modeli. Ve işletim sisteminden farklı iş parçacıklarının kendi uygulaması. Ve kendi yükleyici. Gelişmiş bir hata ayıklama API'sini içeren çalışma zamanı iç gözlemi. Bu kesinlikle sanal bir makinedir. - Ben Voigt
P / invoke etmek zorunda olduğu iş miktarını azaltmak için adres alanı (her halükarda fiziksel makinede sanallaştırılan) gibi fiziksel makine ile pek çok şeyi paylaşmayı seçer. p / invoke ile ilgili türler oldukça fazla iş yapar ve basit türler için bile "argümanları yığına atlamak ve zıplamak" kadar kolay değildir. Her yönetilen / yerel geçiş, çöp toplayıcı durumunu değiştirmeyi, referans ile geçirilen pim parametrelerini ve ayrıca GC'nin yönetilen koda döndükten sonra iş parçacığını duraklatmasına izin vermeyi içerir. - Ben Voigt
@hoodaticus: Ama ben onu "eklemedim", CLR her zaman bu şeyleri yapıyor ve çok ince bir katmanın tanımını desteklemek için onları uygulamanızın dışında bırakmayı seçtiniz. Ancak CLR ile çalışan kod "yerel" değil "yönetilir" ve yönetilen / yerel geçişler karmaşık canavarlardır. Bir çok çalışma, tablo aramalarını (sıfır-yukardaki istisna işlemiyle aynı tür bir yaklaşım) kullanarak yapılsa bile, çağrı sitesinde görünmüyorsa, bu geçişlerin her birinin, potansiyel olarak çöp toplayıcı ile bir senkronizasyon noktası olun. - Ben Voigt


Cevaplar:


Burada birçok yanlış anlama var. Gerçekten bir sanal makine olarak düşünebilirsiniz, eğer gerçekten istediyseniz, ama .Net Framework'ün gerçekten sizin kodunuzu nasıl ele aldığına bakalım. Tipik senaryo böyle görünüyor

  1. C #, VB.Net, F # veya başka bir uyumlu dilde bir .Net programı yazarsınız.
  2. Bu kod, son kullanıcı makinelerine dağıtılan Java'nın bayt koduna benzeyen bir Ara Dili (IL) ile derlenmiştir.
  3. Bir son kullanıcı programı ilk defa bir bilgisayarda .Net'in doğru sürümüyle çağırır.
  4. Bilgisayar, bunun "ham" makine kodu yerine bir Net montaj olduğunu ve JIT derleyicisine aktardığını görüyor
  5. JIT derleyicisi IL'yi tamamen yerel makine koduna derler.
  6. Bu program yürütme ömrü için yerel kod belleğe kaydedilir.
  7. Kaydedilen yerel kod çağrılır ve IL artık önemli değildir.

Burada birkaç önemli nokta var, ama büyük olan hiçbir noktada hiç yorumlanmayan bir koddur. Bunun yerine, 5. adımda yerel kodun derlendiğini görebilirsiniz. Bu bir Kocaman çeşitli nedenlerden dolayı sanal bir makineye yüklemekten farkı:

  1. Tam derlenmiş kod, daha hızlı olması gereken ek bir yazılım soyutlama katmanı tarafından yorumlanması veya çevrilmesi yerine doğrudan cpu tarafından yürütülür.
  2. JIT derleyicisi, en düşük ortak paydaya yerleşmek yerine, programı çalıştıran bireysel makineye özgü optimizasyonlardan yararlanabilir.
  3. İsterseniz kodu önceden derleyebilir ve özü tamamen kullanıcıdan 5. adımı gizleyebilirsiniz.

JITter'in gerçek makinenin detaylarını geliştiriciden soyutladığı düşüncesine göre, bunu sanal bir makine olarak adlandırabilirsiniz. Şahsen bu doğru bir şey olduğunu düşünmüyorum, çünkü birçok insan için sanal bir makine, çalışma zamanı soyutlamasını yerel ağdan uzak tutuyor. mevcut değil.

Bu süreci bir "sanal makine" ortamından ayıran diğer bir anahtar nokta, yalnızca tipik süreci. Gerçekten isterseniz, dağıtımdan önce bir .Net derlemesini önceden derleyebilir ve yerel kodları doğrudan son kullanıcılara dağıtabilirsiniz (ipucu: makineye özgü optimizasyonları kaybettiğiniz için programın ömrü boyunca toplu olarak daha yavaştır). Tabii ki, hala .Net çalışma zamanına ihtiyacınız var, ancak bu noktada diğer herhangi bir çalışma zamanı API'sinden çok farklı değil; Microsoft, Visual Studio ile birlikte gelen VB veya C çalışma zamanlarına sahip olabileceğiniz gibi, bağlantı kurabileceğiniz güzel bir API'ye sahip bir koleksiyon dergisi gibi. Bu tür, IL'yi resimden çıkarır ve VM monikerini haklı göstermek için daha da zorlaştırır. (“Tür” diyorum çünkü IL hala dağıtılmış ve kaydedilen kodu doğrulamak için kullanılıyor, fakat hiçbir zaman uygulama için dokunulamıyor).

Bir diğer önemli nokta ise bir VM sürecinin eksikliğidir. Uygulamanızı çalıştırdığınızda, çalışan genel bir "sanal alan" işlemi yoktur. Bunu Java ile karşılaştırın, burada bir program çalışırken görev yöneticisini açarsanız, özellikle Java VM için bir işlem görürsünüz ve uygulamanın gerçek süreci sanal makine tarafından oluşturulan sanal alanın içindeki bir iş parçacığıdır. .Net'de, uygulamanın işlemlerini Windows görev yöneticisinde doğrudan görürsünüz.

Özetle: IL + CLR + JIT'in bir şekilde bir şekilde sanal bir makine oluşturduğunu söyleyebilirdiniz. Şahsen ben öyle düşünmüyorum, ama buna inanıyorsan seninle tartışmayacağım. Yapmak istediğim nokta, birisine .Net'in başka bir açıklama yapmadan sanal bir makinede çalıştığını söylediğinde, o kişiye ilettiğiniz fikrin "bir ana bilgisayar işleminde bytecode olarak yorumlanması" dir. Ve bu sadece yanlış.


82
2017-10-26 14:19



Java ile aynı şeyi yapmazsa, o zaman bu bir Sanal Makine değil. Bence bu seninle aynı fikirde olmadığım en büyük şey, çünkü o zaman döngüsel bir tanım olma eğilimindedir. - Damien_The_Unbeliever
Joel, yorumlarınıza göre, uygulama başladığında JIT derleyicisinin bir kez ve tüm IL kodunun yerel koda derlediğine inandığını hissettiğimde, aniden durur. Sadece yanlış, JIT, yürütme akışı gerektirdiğinde, yöntemleri anında anında derler. Ayrıca bir VM süreci var. Bu, uygulamanızı çalıştıran CLR'dir. GC, güvenlik modeli, meta veri servisi ile kesinlikle kumlu bir ortam. Çalıştırılan uygulama, .exe'den sonra adlandırılır çünkü Window'un PE yükleyicisi, CLR .net ikili dosyalarına nasıl yetki verileceğini bilir. - Jb Evain
@Joel, hala son paragrafın yanlış. Windows 'PE yükleyici, programı kendi kontrol, bellek ve güvenlik bilgisi dahilinde başlatan CLR'yi başlatır. İçeride kesinlikle kullanılabilir. Bu sadece bir fırlatma a la java, Rotor veya mono önlemek için bir kırılma. Ancak .net EE (yürütme altyapısı), programın nasıl çalıştığını denetler. - Jb Evain
Evet. PE Header yönlendirme, .Net uygulamasını çalıştıran CLR'yi (mscoree) önyükleme yapmak için bir numaradır. Dahası, JB'nin dediği gibi, JIT bir kez ve herkes için yapılmaz ve bazı JITted yöntemleri daha sonra atılabilir ve reddedilebilir. Sanırım yanıltıcı duygular, gözlemcinin gözünde. - Yann Schwartz
Joel, cevabın MS liderini takip ediyor. Net CLR, durdurulan JVM'nin evrimidir. "IL + CLR + JIT", JIT çıktısının işlevi CLR işlevselliğini çoğaltmak olduğunda bir VM'ye eşittir. Bir sürü iddiayı yeniden oluşturmak da dahil olmak üzere, iyi yanıtlanmış bir soruya yönelik garip saldırıyı takdir etmiyorum: Cevabım henüz yanıtlanmamış ve sizin tarafınızdan “yanlış” gibi görünüyor. OP, JVM'yi bir VM olarak değerlendirir, dolayısıyla .Net CLR ayrıca bir VM'dir. Bunların ikisi ya da her ikisi de Sanal Makineler'dir, çünkü sadece işlevsel olarak aynı değil, biri diğerinden kaynaklanır. - Heath Hunnicutt


Java Virtual Machine'e (JVM) benzer şekilde, .net CLR bir bayt kodu yorumlama sanal makinesidir.

JVM, java bayt kodları ve Microsoft'un "Orta Düzey (IL)" yönergelerini çağıranları içeren .net CLR yorumlama programlarını içeren programları yorumlar. Bu bayt kodları arasında farklılıklar vardır, ancak sanal makineler benzer özelliklere sahip olmayı ve benzer özellikler sunmayı amaçlamaktadır.

Bu sanal makine uygulamalarının her ikisi de, giriş bayt kodunu, üzerinde çalıştıkları bilgisayarın makine diline derleme yeteneğine sahiptir. Buna denir "Tam Zamanında Derleme (JIT)" ve üretilen çıkış kodu "JIT kodu" olarak adlandırılır. JIT kodu, bilgisayarın CPU'sunun makine dilindeki talimat dizilerini içerdiğinden, bu kod bazen "yerel" kod olarak adlandırılır.

Ancak, JIT kodu aşağıda açıklandığı gibi, yerel koddan niteliksel ve niceliksel olarak farklıdır. Bu nedenle, bu makale JIT kodunu bir Belirli bir bytecode programı çalıştırırken Sanal Makinenin yerel uygulaması.

Bu Sanal Makinelerin (VM'ler) sağlamayı amaçladığı bir özellik, belirli tehlikeli programlama hatalarının önlenmesi biçiminde güvenliktir. Örneğin, bu web sitesi forumunun başlığı olan stackoverflow, yerel kodda olabilecek böyle bir tür tehlikeli hatadan esinlenmiştir.

Güvenlik ve yürütme güvenliğini sağlamak için VM'ler, "Sanal Makine Seviyesi" nde tip güvenliği uygular. VM belleğe atamalar, o bellek konumunda tutulan veri tipini saklamak için gereklidir. Örneğin, bir tam sayı yığının üzerine itilirse, yığından bir çift çizmek mümkün değildir. C tarzı "sendikalar" yasaktır. İşaretçiler ve belleğe doğrudan erişim yasaktır.

Sonuç, bir EXE dosyası gibi yerel bir ikiliyse, geliştiricilere bir nesne yönelimli dil çerçevesini uygulayarak aynı yararları alamadık. Bu durumda, çerçeve ile oluşturulan yerel ikili dosyaları ve çerçeve dışındaki kaynakları kullanan kötü niyetli bir kullanıcı tarafından oluşturulan EXE'leri ayırt edemeyiz.

VM'ler söz konusu olduğunda, tip güvenliği, programcının erişmesine izin verilen "en düşük seviyede" uygulanır. (Yönetilen yerel kod yazmanın mümkün olduğu bir an için ihmal edilir, yani.) Bu nedenle, hiçbir kullanıcı, bellek konumlarına ve işaretçilere doğrudan erişim gerektiren tehlikeli işlemlerden birini gerçekleştiren bir uygulama ile karşılaşmaz.

Pratikte, .net CLR .net "yönetilen" kodu ile çağrılabilir yerli kod yazmak için bir yol uygular. Bu durumda, yük, yerel kod yazarının işaretçi ve bellek hatalarından herhangi birini yapmamasıdır.

Hem JVM hem de .net CLR, JIT derlemesini gerçekleştirirken, ya VM aslında, sağlanan bayt kodundan bir yerel derlenmiş ikili oluşturur. Bu "JIT kodu", VM'nin yorumlayıcı uygulamasından daha hızlı çalışır; çünkü JIT tarafından üretilen makine dili kodu bile, sanal makinenin gerçekleştireceği tüm VM'nin gerekli güvenlik kontrollerini içerir. Sonuç olarak, JIT çıkış kodu, normalde çok sayıda çalışma zamanı kontrolü içermeyen yerel kod kadar hızlı değildir. Bununla birlikte, bu hız performansı dezavantajı, güvenlik dahil güvenilirliğin iyileştirilmesi için değiştirilmektedir; özellikle, başlatılmamış depolamanın kullanımı engellenir, atamaların tip güvenliği zorlanır, aralık kontrolü yapılır (böylece yığın ve yığın tabanlı tampon taşmaları engellenir), nesne yaşamları çöp toplama tarafından yönetilir, dinamik ayırma tipi güvenlidir. Bu tür çalışma zamanı davranış denetimlerini yürüten bir ortam, sanal bir makinenin belirtimini uygular ve sanal makinenin makine dilinin gerçekleştirilmesinden biraz daha fazladır.


23
2017-10-14 05:25



Katı ayrıntılı bilgilendirici cevap ama umarım bir nit seçersem sorun olmaz. Yönetilen kodda yığın taşması kesinlikle mümkündür: Bunu yeniden oluşturmak için aşağıdaki yöntemi oluşturun ve çağırın: public void f () {f (); }. Fark, hataların daha öngörülebilir ve daha az kullanışsız olma eğiliminde olma eğilimindedir (bu, birisinin yanlışlıkla kod olarak çalıştırılmasını önlemek için tip güvenliği ile bağlantılıdır). Örneğin, hatalı bir işaretçinin C'deki tahmin edilemeyen sonuçlara sahip olması; Ancak, JVM veya CLR'de geçersiz kılma, güvenli ve öngörülebilir bir şekilde size bir istisna verir. Pedantry için özür dilerim! - itowlson
Bu sadece yanlış. Net diller, java bayt koduna benzer olan IL'ye derlenmiştir ve bu, yürütme için kullanıcı bilgisayarlarına dağıtılan IL'dir. Fark, bayt kodu çalıştırılmak üzere bir VM'ye yüklemek yerine .Net IL, yürütmeden önce yerel kod olarak derlenmiştir. Hiç bir sanal makine hiç yüklenmemiş. - Joel Coehoorn
@Joel - elbette yerel kodun derlemesi alakasız bir ayrıntı mıdır? Şimşek hızlı tercümanı olan CLR'nin gelecekteki bir versiyonu bunun yerine yoruma geçebilirdi ve hiç kimse bu gerçeği bilmemeli ... - Damien_The_Unbeliever
@Joel - Sadece biraz netleştirme ... JITting yöntem seviyesindedir, bu nedenle her yöntem ilk kez çağrılmadan hemen önce derlenir. Teknik olarak, JITter önceden programlanmamış bir yöntem çağrıldığında, program yürütme boyunca çağrılır. JITter'in "kapatılması" olacağı tek zaman, kodunuzdaki her yöntem ve türün bir kez daha erişilmiş olması. - ProKiner
Ayrıca Joel'in yorumu ".Net ile kodunuz çalışırken çalışan bir sanal alan ortamı yok." tamamen yanlış. - Ben Voigt


"Sanal Makine" kısmı, .NET kodunun, EXE'lerin ve DLL'lerin, gerçek CPU derleme dilinin tersine, sanal bir makinede çalışacak "Ara" derleme dili (IL) olarak derlendiği gerçeğini ifade eder. Daha sonra, çalışma zamanında ILM, yürütme için gerçek CPU düzeneğine dönüştürülür (Just-in-time veya JIT derlemesi olarak anılır).

Elbette, bir .NET derleyicisini, IL yerine CPU derleme diline derlenecek şekilde yazabilirsiniz. Ancak, bu tüm CPU'lar için taşınabilir olmayacaktır - her bir OS / CPU çifti için farklı bir sürümü derlemeniz gerekir. Ancak, ILM'yi derleyerek, "Sanal Makinenin" CPU ve OS'ye özgü şeyleri ele almasına izin verdiniz.


6
2017-10-14 05:20



Bence IL ya da daha doğrusu CIL - Ortak Orta Düzey. - dahlbyk
Teşekkürler, tamir ediyorum ... - noctonura


Ben biraz eski okulum, bu yüzden CLR'yi sanal bir makine olarak da adlandırıyorum. Benim mantığım, CLR'nin makine kodunu, bir sanal makinenin de yaptığı bir ara bayt koduyla birleştirmesidir.

CLR'nin faydaları, esas olarak, çalışma zamanı türü bilgisini kullanan makine kodunu bir araya getirme biçiminden kaynaklanmaktadır.

Sadece yerel türleri kullanarak .NET çerçevesi kadar güçlü bir yerel çerçeve geliştirebilirsiniz. Kaybettiğiniz tek esneklik, programınızı başka bir platforma yeniden derleme yapmadan aktarırsanız, yerel kodu yeniden kurmanızdır.


2
2017-10-14 05:23



Bir ara temsilden makine hedefli talimatlar oluşturmak, geldiğim yerde derleme olarak adlandırılır. - hoodaticus


CLR'nin avantajı, geliştiricinin seçtiği programlama dilinde kod yazabilme özgürlüğüdür, çünkü kod, yerel çağrılar olarak yorumlanmadan önce CLR'ye derlenecektir. .NET çerçevesi, bu JIT derlemesini her şeyi tek tek ele almak ve derlenen dillerden yoksun olan platform için çalışan programların çıktılarını almak için kullanır.


2
2017-10-14 05:21



"yerel çağrılar olarak yorumlandı" sadece yanlıştır ... - Ben Voigt
Bu nasıl yanlış? VM, CLR bayt kodunu yerel CPU talimatlarına çeviriyor, değil mi? - Ben Lakey
Yorumunuz doğru: "Orta Dil" adlı yerel makine koduna CLR bayt kodu derler (çevirir). Bu değil yorumlama. Yorumda, program veridir; Çalışma zamanı kodu, verilerdeki koşulları test eder ve çalışma zamanı içindeki diğer kodlara atlar; İşlemci talimatı işaretçisi, yalnızca çalışma zamanı içinde mevcut olan kodu değiştirir. Derleme sırasında program, işlemci üzerinde çalıştırılan bir kod bölümüne dönüştürülür (çalışma zamanı kitaplığı kodu, derlenmiş program koduyla çağrıldığında hala çalışır, ancak çalışma zamanında tüm kodlar önceden mevcut değildir). - Ben Voigt


Ne JVM ne de CLR, diğer diller için çoğu “sanal makinenin” yaptıklarından çok farklı bir şey yapmıyor. Modern olarak, hepsi sanal komutları (p-kodu, bayt kodları, ara dil komutları, istediğiniz her şeyi) yerel işlemci donanımına ("makine kodu") dönüştürmek için JIT kullanıyorlar.

Aslında, bunu yapmak için ilk "sanal makine" Smalltalk sanal makine oldu. Bu yeniliğin yazarı Peter Deutsch, Java tarafından popüler hale getirilen "JIT" terimi yerine "dinamik çeviri" olarak adlandırdı. Eğer Smalltalk "çalışma zamanı yürütme ortamı" bir "sanal makine" olarak adlandırılacaksa (ve buna hala denir), o zaman esasen aynı şeyi yapan diğer tüm "çalışma zamanı sistemleri" de "sanal makineler" olarak nitelendirilir. "


2
2017-07-03 22:28



JVM ayrıca kodu çalıştırmak için bir tercüman kullanır; Masaüstü .NET'in CLR'si gibi saf bir derleme modeli değildir. Materyal olarak farklı çünkü .NET ara dili JIT derlemesi varsayımıyla tasarlanırken - biri bir tercüman yazabilirken, performans kötü olurdu, bytecode formatının yorumlama için optimize edildiği Java yorumlayıcısından çok daha kötü olurdu. - Ben Voigt
Ama evet, hala bir sanal makine. - Ben Voigt


Çok değerli cevabınız var, ama bence henüz bir şey söylenmedi: Modülerlik.

Bir OO sınıfını yerel DLL'den dışa aktarmak oldukça zor. Tabii ki, bağlayıcıya sınıfı ihraç etmek ve başka bir yere almak için söyleyebilirsin, ama bu kırılgandır; Bir sınıftaki tek bir özel üyeyi değiştirmek, ikili uyumluluğu bozar, yani, tüm diğer modülleri yeniden derlemeden bir DLL değiştirirseniz, programınız çalışma zamanında korkunç bir şekilde çökecektir.

Bununla ilgili bazı yollar vardır: Örneğin, genel soyut arabirimleri tanımlayabilir, bunlardan türetebilir ve genel fabrika işlevlerini DLL'nizden dışa aktarabilirsiniz. Bu şekilde, bir sınıfın uygulama ayrıntılarını değiştirebilirsiniz. Ancak başka bir DLL'de bu sınıftan türetilemezsiniz. Arabirimi değiştirmek de, elbette ki ikili uyumluluğu bozar.

Yerel kodda bunun için iyi bir çözüm olup olmadığından emin değilim: Derleyici / linker derleme zamanında yerel kod oluşturuyorsa, kodda kullanılan sınıfların / yapıların tam olarak bellek düzenini bilmesi gerekir. Son derleme adımı (yerel kod oluşturma), ilk kez bir yöntem çağrılana kadar ertelenirse, bu sorun basitçe gider: bir derlemede bir sınıfı değiştirebilir ve JIT tüm kullanılmış üyeleri çözebilir. işlem esnasındaher şey yoluna girecek.

Özetle: Bir monolitik tek yürütülebilir program oluşturursanız, büyük olasılıkla .NET'in güçlü özelliklerinin çoğunu yerel kod oluşturan bir derleyiciyle edinebilirsiniz. Ancak bir JIT derleyicisine sahip olmanın dezavantajları (çerçeve kurulumu, biraz daha uzun başlatma süreleri) çoğu durumda yararlarından daha fazla değildir.


1
2017-10-26 15:06