溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

互聯(lián)網(wǎng)中托管程序與非托管程序有什么區(qū)別

發(fā)布時(shí)間:2021-12-03 16:51:46 來源:億速云 閱讀:129 作者:小新 欄目:編程語(yǔ)言

這篇文章主要為大家展示了“互聯(lián)網(wǎng)中托管程序與非托管程序有什么區(qū)別”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“互聯(lián)網(wǎng)中托管程序與非托管程序有什么區(qū)別”這篇文章吧。

托管代碼是一microsoft的中間語(yǔ)言,他主要的作用是在.NET FRAMEWORK的CLR執(zhí)行代碼前去編譯源代碼,也就是說托管代碼充當(dāng)著翻譯的作用。

什么是托管代碼?

托管代碼就是Visual Basic .NET和C#編譯器編譯出來的代碼。編譯器把代碼編譯成中間語(yǔ)言(IL),而不是能直接在你的電腦上運(yùn)行的機(jī)器碼。中間語(yǔ)言被封裝在一個(gè)叫程序集(assembly)的文件中,程序集中包含了描述你所創(chuàng)建的類,方法和屬性(例如安全需求)的所有元數(shù)據(jù)。這個(gè)程序集是.NET世界中的一個(gè)一站式購(gòu)物(譯者注:就是程序集具有自描述性)部署單元。你可以拷貝這個(gè)程序集到另一臺(tái)服務(wù)器上部署它--通常來說,這個(gè)拷貝的動(dòng)作就是部署流程中***的一個(gè)操作。

托管代碼在公共語(yǔ)言運(yùn)行庫(kù)(CLR)中運(yùn)行。這個(gè)運(yùn)行庫(kù)給你的運(yùn)行代碼提供各種各樣的服務(wù),通常來說,他會(huì)加載和驗(yàn)證程序集,以此來保證中間語(yǔ)言的正確性。當(dāng)某些方法被調(diào)用的時(shí)候,運(yùn)行庫(kù)把具體的方法編譯成適合本地計(jì)算機(jī)運(yùn)行的機(jī)械碼,然后會(huì)把編譯好的機(jī)械碼緩存起來,以備下次調(diào)用。(這就是即時(shí)編譯)

隨著程序集的運(yùn)行,運(yùn)行庫(kù)會(huì)持續(xù)地提供各種服務(wù),例如安全,內(nèi)存管理,線程管理等等。這個(gè)程序被“托管”在運(yùn)行庫(kù)中。

Visual Basic .NET和C#只能產(chǎn)生托管代碼。如果你用這類語(yǔ)言寫程序,那么所產(chǎn)生的代碼就是托管代碼。如果你愿意,Visual C++ .NET可以生成托管代碼。當(dāng)你創(chuàng)建一個(gè)項(xiàng)目的時(shí)候,選擇名字是以.Managed開頭的項(xiàng)目類型。例如.Managed C++ application。

什么是非托管代碼?

非托管代碼就是在Visual Studio .NET 2002發(fā)布之前所創(chuàng)建的代碼。例如Visual Basic 6, Visual C++ 6, 最糟糕的是,連那些依然殘存在你的硬盤中、擁有超過15年歷史的陳舊C編譯器所產(chǎn)生的代碼都是非托管代碼。托管代碼直接編譯成目標(biāo)計(jì)算機(jī)的機(jī)械碼,這些代碼只能運(yùn)行在編譯出它們的計(jì)算機(jī)上,或者是其它相同處理器或者幾乎一樣處理器的計(jì)算機(jī)上。非托管代碼不能享受一些運(yùn)行庫(kù)所提供的服務(wù),例如安全和內(nèi)存管理等。如果非托管代碼需要進(jìn)行內(nèi)存管理等服務(wù),就必須顯式地調(diào)用操作系統(tǒng)的接口,通常來說,它們會(huì)調(diào)用Windows SDK所提供的API來實(shí)現(xiàn)。就最近的情況來看,非托管程序會(huì)通過COM接口來獲取操作系統(tǒng)服務(wù)。

跟Visual Studio平臺(tái)的其他編程語(yǔ)言不一樣,Visual C++可以創(chuàng)建非托管程序。當(dāng)你創(chuàng)建一個(gè)項(xiàng)目,并且選擇名字以MFC,ATL或者Win32開頭的項(xiàng)目類型,那么這個(gè)項(xiàng)目所產(chǎn)生的就是非托管程序。

這樣子會(huì)導(dǎo)致一些混淆:當(dāng)你創(chuàng)建一個(gè)托管的C++程序,那么構(gòu)建出來的是一個(gè)中間語(yǔ)言程序集和一個(gè)擴(kuò)展名為.exe的可執(zhí)行文件。當(dāng)你創(chuàng)建一個(gè)MFC程序,構(gòu)建出來是一個(gè)Windows原生代碼的可執(zhí)行文件,這個(gè)文件的擴(kuò)展名也是.exe。這兩個(gè)文件的內(nèi)部結(jié)構(gòu)是完全不一樣的。你可以用中間語(yǔ)言反匯編器(ildasm)來查看程序集的內(nèi)部以及中間語(yǔ)言的元數(shù)據(jù)。如果嘗試用中間語(yǔ)言反匯編器來查看一個(gè)非托管可執(zhí)行文件,那么改反匯編器會(huì)告訴你這個(gè)可執(zhí)行文件沒有包含一個(gè)合法的CLR頭,所以不能被反編譯??梢?,這兩個(gè)文件雖然有相同的擴(kuò)展名,但是它們是完全不一樣的。

原生代碼又是什么呢?

原生代碼這個(gè)短語(yǔ)可以用在兩個(gè)不同的上下文中。很多人會(huì)把原生代碼跟非托管代碼看作是同一個(gè)意思:用較老的工具構(gòu)建的代碼,故意采用Visual C++并使直接運(yùn)行在計(jì)算機(jī)上,而且不運(yùn)托管在運(yùn)行庫(kù)中。這可以是一個(gè)完整的程序,或者是一個(gè)COM組件,又或者是一個(gè)可以被托管代碼利用COM Intero或者平臺(tái)調(diào)用(PInvoke)所調(diào)用的DLL文件,COM Intero或者平臺(tái)調(diào)用(PInvoke)可以幫助你在遷移到新的技術(shù)平臺(tái)下依然能重用老代碼的兩個(gè)強(qiáng)大工具。

我更愿意說是非托管代碼,因?yàn)檫@強(qiáng)調(diào)的是那些不能利用運(yùn)行庫(kù)所提供的服務(wù)的代碼。例如在托管代碼中,代碼訪問安全服務(wù)可以防止在另一個(gè)服務(wù)器上裝載的代碼運(yùn)行特定的操作。如果你的代碼運(yùn)行的是非托管代碼,那么你沒法利用這樣的保護(hù)服務(wù)。

原生代碼的另一個(gè)意思是描述即時(shí)編譯器的輸出,那些實(shí)際上運(yùn)行在運(yùn)行庫(kù)中的機(jī)械碼。這些代碼是托管代碼,但是并不是中間語(yǔ)言,而是機(jī)械碼。所以不要簡(jiǎn)單地假設(shè)原生就是等同于非托管。

托管代碼就意味著托管數(shù)據(jù)?

對(duì)于Visual Basic和C#來說,生活是簡(jiǎn)單的,因?yàn)槟銢]有其它選擇。當(dāng)你在那些語(yǔ)言里面聲明一個(gè)類,那么這個(gè)類的實(shí)例會(huì)在托管堆中被創(chuàng)建,垃圾收集器(GC)會(huì)幫我們管理這些對(duì)象的回收。但是在Visual C++中,你有另一個(gè)選擇。即使你正創(chuàng)建一個(gè)托管程序,你可以決定哪些類是托管類型,哪些類是非托管類型的。

這就是非托管類型:

class Foo  {  private:  int x;  public:  Foo(): x(0){}  Foo(int xx): x(xx) {}  };

這就是托管類型

__gc class Bar  {  private:  int x;  public:  Bar(): x(0){}  Bar(int xx): x(xx) {}  };

他們***的區(qū)別就是類Bar的定義中有__gc關(guān)鍵字。這個(gè)關(guān)鍵字會(huì)給代碼帶來巨大的區(qū)別。

托管類型是可以被垃圾回收器所回收的。他們必須要用關(guān)鍵字new來創(chuàng)建,永遠(yuǎn)都不會(huì)在棧中出現(xiàn)。所以下面這行代碼是合法的:

Foo f;

但是這一行代碼就是非法的:

Bar b;

如果我在堆中創(chuàng)建一個(gè)Foo對(duì)象,那么我必須要負(fù)責(zé)清理這個(gè)對(duì)象:

Foo* pf = new Foo(2);  // . . .  delete pf;

C++編譯器實(shí)際上會(huì)用兩個(gè)堆,一個(gè)托管堆和一個(gè)非托管堆,然后通過對(duì)new操作符的重載來實(shí)現(xiàn)對(duì)創(chuàng)建不同類型類的實(shí)例,分配不同的內(nèi)存。

如果我在堆里面創(chuàng)建一個(gè)Bar實(shí)例,那么我可以忽略它。當(dāng)沒有其他代碼在使用它的時(shí)候,垃圾回收器會(huì)自動(dòng)清理這個(gè)類,釋放其占用的資源。

對(duì)于托管類型會(huì)有一些約束:它們不能實(shí)現(xiàn)多重繼承,或者繼承與非托管類型;它們不能用friend關(guān)鍵字來實(shí)現(xiàn)私有訪問,它們不能實(shí)現(xiàn)拷貝構(gòu)造函數(shù)。所以,你有可能不想把你的類聲明為托管類型。但是這并不意味著你不想讓你的代碼成為托管代碼。在Visual C++中,你可以選擇。

托管和非托管資源,是C#中的事,就不在這討論了。

托管代碼與非托管代碼的性能比較

基本上每個(gè)人都知道的是,所有.Net語(yǔ)言都將被編譯成為一個(gè)叫做IL匯編的中間語(yǔ)言。但是計(jì)算機(jī)是如何執(zhí)行這個(gè)中間代碼的,卻是很多人不知道,甚至理解錯(cuò)誤了的。

JIT是.NET程序運(yùn)行的重要部件之一,全稱是即時(shí)編譯器。我剛才說的誤解,就是很多人(絕對(duì)不是少數(shù),問了很多c++程序員,10個(gè)有9個(gè)這種想法)都以為JIT其實(shí)就是跟Java VM差不多的東西,是一個(gè)Interpreter,在運(yùn)行時(shí)讀取IL匯編代碼,然后模擬成x86代碼(也就是俗稱的虛擬機(jī))。但是事實(shí)上,.NET使用的是更為高級(jí)的技術(shù)。 .Net程序被加載入內(nèi)存以后,當(dāng)某段IL代碼被***次運(yùn)行的時(shí)候,JIT編譯器就會(huì)將這段IL代碼,全部編譯成本地代碼,然后再執(zhí)行。這也就是為什么.NET程序***次運(yùn)行都啟動(dòng)很慢的原因!

隨.NET庫(kù),微軟還附帶了一個(gè)工具,可以事先將.NET程序所有的IL代碼都編譯成本地代碼并保存在緩存區(qū)中,這樣一來,這個(gè)程序就跟c++編譯的一模一樣了,沒有任何區(qū)別,運(yùn)行時(shí)也可以脫離JIT了(這里不要混淆了,這里不是說可以脫離.NET庫(kù),而是說不需要在進(jìn)行即時(shí)編譯這個(gè)過程了)。所以,請(qǐng)不要將.NET和Java混為一談,兩個(gè)的運(yùn)行效率根本不是一個(gè)等級(jí)的!

JIT的優(yōu)化指的是可以針對(duì)本地CPU,在編譯時(shí)進(jìn)行優(yōu)化。傳統(tǒng)程序在編譯時(shí),為了保證兼容性,通常使用最通用的指令集(比如古老的386指令集)來編譯。而JIT知道CPU的具體類型,可以充分利用這些附加指令集進(jìn)行編譯,這樣的性能提升是很可觀的。

以上是“互聯(lián)網(wǎng)中托管程序與非托管程序有什么區(qū)別”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI