1:JIT(即時編譯)。一個方法在第一次調用時JIT會把改方法的IL代碼轉換成CPU指令,再次調用該方法時就只需執行對應的指令。方法第一次被調用的過程大致是:1獲得方法的IL代碼;2:分配內存;3:將IL代碼轉換成CPU指令存在2分配的內存中;4:將方法表中對應該方法的指針指向2分配的內存;5:跳轉到2分配的內存執行其中的指令,即該方法的CPU指令。
2:as的性能高於is。Is的作用是判斷當前類型與目標類型是否兼容,即是否是同一類型或者目標類型是當前類型的父類型。強制類型轉換也要判斷類型的兼容性,如果不兼容就拋出一個類型轉換異常,如果你的代碼類型轉換用Is+強制類型轉換就做了兩次兼容性判斷,而as只有一次類型轉換。
3:C#中的int對應FCL中的Int32,long對應FCL中的Int64,同一類型,64位CPU所需存儲的空間是32位CPU的2倍。
4:string是引用類型,常量字符串都存在字符串池中,如果一個字符串在代碼中多次出現,那么這些都是對字符串池的引用,string s="a"+"b";只分配了一次內存,編譯器會直接將其編譯成string s="ab";s是對字符串池中ab的引用。
5:大量字符串的拼接用StringBuilder,少量則用字符串相加,能用+=則更好,string.format的效率是低下的,它的內存其實是params object[] +StringBuilder,params也是低效的,字符串相加,或是取其中的一部分都是要重新分配內存,然后將對應的字符串存入。FCL大部分代碼都是用C#寫的,而操作字符串這一塊用的是非托管代碼寫的,處於對性能的考慮。
6:別看到new就以為會在托管堆中分配內存,值類型的變量就是分配中線程棧上的,結構體雖然可以用new,但是編譯器推斷出它是值類型,就會按照值類型的處理,當然IL代碼中是沒有newobj指令的。
7:靜態類被編譯成sealed abstract類型,所以他不能被繼承,不能被實例化,所以他的屬性和方法都是屬於類型的,沒有屬於對象的,它必須直接繼承Object。
8:const和readOnly的區別,IL代碼中存的是const變量的值,而不是引用,所以修改是不可能的,如果一個DLL只引用了另一個DLL中的一個const變量,那么這個DLL是不會被引用的,因為編譯的時候就知道變量的值了,所以在運行的時候也不會分配內存,readonly表示你不能修改它的指向,但是可以修改它所指向變量的值。
9:泛型,C#中的泛型和C++的模版區別在於引用類型,C++模版會每一種類型都會生成一個新的類型(引用類型是不會的),而C#泛型中,引用類型用的是同一個類型,只有值類型用的是不同的類型。因為引用都是一個指針的引用,而值類型存儲所需的空間是不同的。在C++中有模版半特化,將T 半特化成void*,這樣指針類型就不用再生成一套代碼了
其他基礎知識,請看這篇博客:這些天寫的技術微博
作者:陳太漢