我們先不說主題,先說說CLR支持多語言。 .net有個很是強大的特色,那就是跨語言,支持不少語言,好比C#、J#等。先來個圖看一看數組
C# J# VB 等等等 👇 👇 👇 👇 C#編譯器 J#編譯器 VB編譯器 編譯器 👇 👇 👇 👇 --------------------------------- | 中間語言 | --------------------------------- 👇 編譯(運行) 👇 機器語言
看到這個圖,每一個語言都有本身的編譯器,經過第一次編譯,編譯成中間文件(dll或是exe文件)。在程序運行的時候,再次編譯把中間文件編譯成機器語言。安全
可是,CLR支持這麼多語言不會出爲題麼?換句話說是爲何CLR會支持這麼多語言?ruby
就像一個四川人和一個河南人對話,互相的聽不懂,可是,他們兩我的都說普通話就能交流了。在CLR中,每種語言就至關於各個地方的人們,相互交流困難,可是有了普通話這個規範(CTS(公共語言類型)和CLS(公共語言規範)),就能夠說話了。CTS至關於咱們普通話的音節,而CLS至關於普通話的約定的語法。這樣子呢,就組成了.net你們庭。在CTS中,就是值類型和引用類型服務器
原本想單獨整理一下進程和線程的,後來想和堆棧一塊兒簡單的說更好多線程
在一個應用程序中,會分配一個進程和最大4G的內存空間,這個內存空間會分爲4個區,全局數據區、代碼區、線程堆棧區、託管堆區。less
(線程是程序運行的最小單位,線程之間是隔離的,在Window下,每一個程序都會有主進程,分配的內容最大爲4G)性能
整個項目都是在這個進程運行的。在這個進程中,可能有不少線程,每個線程都會在棧下分配一個1M的託管堆棧的空間。ui
全局數據區:存放着全局變量、靜態數據、常量
代碼區:存放全部的程序代碼
線程堆棧區:存放爲運行而分配的局部變量、參數、返回數據、返回地址
託管堆區:自由存儲區
--------------------------------------------------------------------------------
| ---------------------------------------- -------------------- | | | ---- --- --- ---- | | | | | | |線| |線| |線| |線| | | | | | | |程| |程| |程| |程| | | | | | | |1 | |2| |3| | 3| | | 託 管 堆 | | | | ---- --- --- ---- | | | | | | (線程數量取決於你的代碼) | | | | | | 線 程 堆 棧 | | | | | ---------------------------------------- -------------------- | | | | | | ------------------------------- ----------------------------------- | | | | | | | | | 全 局 數 據 區 | | 代 碼 區 | | | | | | | | | | | | | | | ------------------------------- ----------------------------------- | --------------------------------------------------------------------------------
C#中,通常狀況下值類型存在它申明的地方,引用類型存在託管堆上。值類型轉換引用類型叫裝箱,引用類型轉換值類型叫拆箱lua
對於值類型的實例,CLR在運行時有兩種分配方式: (1) 若是該值類型的實例做爲類型中的方法(Method)中的局部變量,則該實例被建立在線程棧上; (2) 若是該值類型的實例做爲類型的成員,則該實例做爲引用類型(引用類型在GC堆或者LOH上建立)的實例的一部分,被建立在GC堆上
對於引用類型的實例,CLR在運行時也有兩種分配方式:
(1) 若是該引用類型的實例的Size<85000Byte,則該實例被建立在GC(Garbage Collection)堆上(當CLR在分配和回收對象時,GC可能會對GC堆進行壓縮); (2) 若是該引用類型的實例的Size>=85000byte,則該實例被建立在LOH(Large Object Heap)上(LOH不會被壓縮)。
說到了這裏,鋪墊也Ok了,下面有一個題: 在不考慮多線程的條件下,定義了個結構StructObj,裏面有int類型的變量x;又定義了一個類ClassObj,裏面也有int類型的變量x。spa
ClassObj r1 = new ClassObj();//在堆上分配 StructObj v1 = new StructObj();//在棧上分配 r1.x = 5;//根據地址找到引用類型,進行修改 v1.x = 5;//在棧上修改 ClassObj r2 = r1;//只複製引用 StructObj v2 = v1;//在棧上分配空間並複製成員 v2.x = 6; r2.x = 6; Console.WriteLine("v2.x=" + v2.x); Console.WriteLine("r2.x=" + r2.x); Console.WriteLine("v1.x=" + v1.x); Console.WriteLine("r1.x=" + r1.x); Console.WriteLine(r1.Equals(r2).ToString()); Console.WriteLine(v1.Equals(v2).ToString());
如今的打印結果是什麼? 答案是:
v2.x=6 r2.x=6 v1.x=5 r1.x=6 True False
來個圖理解下
線程堆棧 託管堆
r1-------| v1.x=5 |------R=6(r2從新賦值前這個值爲5) r2-------| v2.x=6
畫的比較抽象,r1是引用類型,r1的值存在聲明他的地方,在棧上存的是託管堆的地址,賦值r1.x=5,v1.x=5 再次實例化了,StructObj被存儲在了他聲明的地方,又在棧上開闢了一個空間存儲x=6,r2實例化只是在複製了引用,再次賦值的時候會覆蓋原先的5,那麼r1.x和r2.x值就會相等,說的明白點就是r1和r2就是一個東西。
那麼r1就會和r2徹底相等(值,地址等等) 比較值類型只會比較他們的值是否相等,因此爲False
要是仍是看不懂,這還能怪我咯(有本事你來打我)
忽然想到一個有意思的問題:爲何要分值類型個引用類型?
早在C#出現以前就已經存在了值類型和引用類型。着麼說呢,也應該是一種無奈把。在Window下的應用程序,一個應用程序下假設有四個線程,每個線程都會分配一個1M的空間,那麼4個線程就是4M的空間。先來了一個1.2M的包存進去了,又來了一個1.2的包存進了,如今來了個3M的包發現不足了,這 是他不會開闢新的空間,可能釋放了一個1.2包還存不進去。這是就有內存碎片產生了。若是把因此的數據都當值類型用,線程堆棧區很快就會滿了並且丟出不少內存碎片拖慢服務器速度。那麼我將大的數據存在託管堆上,在線程堆棧上保存一個我在託管堆存放數據的地址,而值類型是一些很小的數據,而且是線程運行的時候才能使用的,因此放在了線程堆棧上。而引用類型裏面可能有不少東西,數據比較大,就存在了託管堆上
如今再來談裝箱和拆箱
裝修是將值類型轉換成object,再將包裝後的對象存儲在堆上的一個過程。而拆箱是從object到值類型的轉換,先檢查對象,確保他是給定值類型的一個裝箱值後。將值複製到新的值類型中,釋放當前對象 由此看來,不論是裝箱仍是拆箱,都須要CPU大量的計算
數組被大部分語言支持,其優勢在因而連續存儲的,因此他的索引速度是很是的快,並且賦值與修改元素也很簡單,訪問速度較快。缺點是數組是定長的,在建立的時候,就須要知道其大小。並且插入數據和刪除很費勁。 相對於數組來講,ArrayList解決了數據的問題,能夠很靈活的插入數據和刪除。因爲ArrayList對數據類型並不嚴格要求,在添加的時候使用object類型來容納添加的對象,這裏會有裝箱拆箱的操做,照成了性能的損失。
爲了解決這種問題,微軟推出了泛型集合List,以下
List<int> list=new List<int>();
能夠看到,在定義泛型集合的時候已經指定了類型。
由於泛型指定了類型,因此在存取的時候值限制於限定的類型內。這樣就避免看裝箱拆箱所消耗的性能問題,又同時提升了安全性
而後再說說泛型,在這裏須要特別說明的是,泛型不能直接的說是值類型仍是引用類型,而是指定類型.
在工做總,經常會遇到泛型的代碼,我在操做的時候不須要在意你是什麼類型,你給我傳過來是什麼類型我就處理什麼類型,或是你須要什麼類型我給你什麼類型。好比:
public class Www<T> where T: ClassObjP { public Www() { } }
在這裏,T表示任意類型,可是,T只是個符號,不是關鍵字,寫A、B、Z等等等等均可以。ClassObjP表示是約定的類,約定製定類的範圍(這類以及這個類的兒子),遵循歷史替換原則的類(原諒本身表達能力)
好了,總結的夠多了。如今最後在拓展一下
上面剛剛在約束裏過了一下,也提了下歷史替換原則,而在工做中,咱們又很小的可能會遇到一些由於沒有遵循里氏替換原則的代碼而報錯,這裏就可能用獲得協變逆變
從使用上來講:協變是子類轉父類,只能用在輸出參數out;逆變是父類轉子類,只能用在輸入參數
在用法上呢,可使用協變,可使用逆變,也能夠協變和逆變輔助使用