學習劉鐵猛老師《C#語言入門詳解》視頻,針對其中重點知識點進行總結。 1、什麼是類型? 類型又稱為數據類型(Data Type),數據類型在數據結構中的定義是一個值的集合以及定義在這個值集上的一組操作。 可以簡單理解為數據在記憶體中存儲的“型號”;小記憶體容納大尺寸數據會丟失精準度,發生錯誤;而大記憶體容 ...
學習劉鐵猛老師《C#語言入門詳解》視頻,針對其中重點知識點進行總結。
1、什麼是類型?
類型又稱為數據類型(Data Type),數據類型在數據結構中的定義是一個值的集合以及定義在這個值集上的一組操作。
可以簡單理解為數據在記憶體中存儲的“型號”;小記憶體容納大尺寸數據會丟失精準度,發生錯誤;而大記憶體容納小尺寸數據會導致浪費。
還應註意編成語言的數據類型與數學中的數據類型不完全相同,例如數學中 3/4=0.75 而在C# 語言中 3 /4 =0。
不同的編程語言對數據類型的約束程度不一樣,所以有強類型編程語言和弱類型編程語言的區分。
變數是用來存儲值得所在處,它們有名字和數據類型。變數的數據類型決定瞭如何將代表這些值的位存儲到電腦的記憶體中。
我們都知道,電腦的世界是二進位的,僅僅用0和1就構建了所有的表達,電腦用來存儲0或者1的單位就是位(bit),8個位組成一個位元組(byte)。
2、數據類型在C#語言中的作用
一個C#類型中所包含的信息有:
- 存儲此類型變數所需的記憶體空間大小 如 int 類型需要4個位元組也就是4*8=32位進行存儲
- 此類型的值可表示的最大、最小值範圍 sbyte占一個位元組8位,s首碼表示帶符號位,取值範圍-128到127,byte占一個位元組,不帶符號位,取值範圍位0-255。
- 此類型所包含的成員(如方法、屬性、事件等) 可以用於ide的錯誤識別和反射時動態調用
- 此類型由何基類派生而來
- 程式運行的時候,此類型的變數在分配在記憶體的什麼位置(棧或堆)
- 此類型所允許的操作(運算)
3、程式的記憶體使用分析
- Stack簡介:函數調用使用,函數調用實際可以理解位棧幀的入棧出棧操作。空間較小,一般1-2M
- Stack overflow 空間較小所以會出現棧空間溢出的情況。例如遞歸函數未正常結束。
- Heap簡介:用來存儲對象(實例)使用,空間較大,可以達到數G
- 使用Perfomance Monitor觀察記憶體使用情況
- 關於記憶體泄漏 未使用的對象未賦值為null導致垃圾收集器未處理,導致空間浪費,這稱為記憶體泄漏。
這裡給出觀察記憶體使用情況的一個樣例,新增的wpf程式,使用Winform程式也是可行的。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents; 10 using System.Windows.Input; 11 using System.Windows.Media; 12 using System.Windows.Media.Imaging; 13 using System.Windows.Navigation; 14 using System.Windows.Shapes; 15 16 namespace HeapSample 17 { 18 /// <summary> 19 /// MainWindow.xaml 的交互邏輯 20 /// </summary> 21 public partial class MainWindow : Window 22 { 23 public MainWindow() 24 { 25 InitializeComponent(); 26 } 27 28 List<Window> winList; 29 30 private void Btn_Consume_Click(object sender, RoutedEventArgs e) 31 { 32 winList = new List<Window>(); 33 for (int i = 0; i < 20000; i++) 34 { 35 Window wd = new Window(); 36 winList.Add(wd); 37 } 38 } 39 40 private void Btn_ClearHeap_Click(object sender, RoutedEventArgs e) 41 { 42 winList.Clear(); 43 } 44 } 45 }
至於Perfomance Monitor觀察記憶體使用情況,可以查看 https:////www.cnblogs.com/FreeLoopPowter/p/12298482.html 。
4、C# 數據類型系統
C#的五大數據類型
- 類(class):如 Form,Window,Console.String
- 結構體(structres):如 Int32,Int64,SIngle,Double
- 枚舉(Enumerations):如Visibility,WindoState
- 介面(Interfaces)
- 委托(Delegate)
C#類型的派生譜系
這裡順帶提一點,我們經常在編輯器中使用結構體時,例如定義一個32位的整型變數時,我們基本使用 int a=5; 這樣的形式,這並不是前面說的結構體類型包含的內容,為啥沒有報錯呢?
這是由於某些數據類型如此常用,以至於許多編輯器允許代碼以簡化語法來操縱它們(也叫關鍵字)。這種語法不僅增強了代碼的可讀性和書寫的方便性,生成的IL代碼還與使用對應的FCL類庫中的類型一致。
這類編譯器能直接支持的類型稱為 基元類型。基元類型直接映射到Framework類庫(FCL)中存在的類型,可以通過按 F12 查看定義,就可以看到映射的FCL類型。
查看CLR Via C#一書,發現其對值類型和引用類型的闡述非常明瞭,還包括了對值類型和引用類型記憶體分配的講解。這裡選取重要內容進行記錄,方便自己後續溫習。對數據類型的記憶體分配情況的分析有利於後續理解方法的傳值參數、引用參數、輸出參數的理解。
CLR支持兩種類型:引用類型和值類型。雖然FCL的大多數類型都是引用類型,但程式員使用最多的還是值類型。引用類型總是從托管堆中分配,C#的new 操作符返回對象記憶體地址——即指向對象數據的記憶體地址。使用引用類型必須留意性能問題,首先認清楚以下四個事實。
- 記憶體必須從托管堆分配。
- 堆上分配的每個對象都有一些額外成員。
- 對象中的其他欄位(為欄位而設)總是設為零。
- 從托管堆分配對象時,可能強制執行一次垃圾回收。(當垃圾回收器發現記憶體不夠時會強制執行一次垃圾回收)
如果所有類型都是引用類型,應用程式的性能將顯著下降。設想每次使用 Int32 時都進行一次記憶體分配,性能會收到多麼大的影響!為了提升簡單和常用的數據類型的性能,CLR提供了名為“值類型”的輕量級類型。值類型的實例一般是線上程棧上分配(雖然也可作為欄位嵌入引用類型的對象中),在代表值類型實例的變數中不包含指向實例的指針。變數中包含了實例本身的欄位。由於變數已包含了實例的欄位,所以操作實例中的欄位不需要提取指針。值類型的實例不受垃圾回收器的控制。因此,值類型的使用緩解了托管堆的壓力,並減少了應用程式生存期間的垃圾回收次數。
下麵給出一個示例,結合圖示講解值類型和引用類型的區別。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace RefTypeAndValueTypeApp 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 //在堆上分配空間 14 SomeRef r1 = new SomeRef(); 15 //在棧上分配空間 16 SomeValue v1 = new SomeValue(); 17 r1.x = 5;//提取指針,給指針引用的對象賦值 18 v1.x = 5;//在棧上修改,由0修改為5 19 Console.WriteLine(r1.x);//顯示 "5" 20 Console.WriteLine(v1.x);//同樣顯示 "5" 21 //以上記憶體分配情況見圖左邊 22 23 //只複製引用(指針) 24 SomeRef r2 = r1; 25 //在棧上分配並複製成員 26 SomeValue v2 = v1; 27 r1.x = 8;//r1.x 和 r2.x 都會改變 28 v1.x = 9;//v2.x會改變 v1.x不會改變 29 Console.WriteLine(r1.x);//顯示 "8" 30 Console.WriteLine(r2.x);//同樣顯示 "8" 31 Console.WriteLine(v1.x);//顯示 "9" 32 Console.WriteLine(v2.x);//顯示 "5" 33 //以上部分程式執行的記憶體分配情況見圖右側 34 35 //讓控制台等待輸入,有輸入後才終止 36 Console.ReadKey(); 37 } 38 } 39 /// <summary> 40 /// 引用類型 41 /// </summary> 42 class SomeRef 43 { 44 public Int32 x; 45 } 46 47 /// <summary> 48 /// 值類型 49 /// </summary> 50 struct SomeValue 51 { 52 public Int32 x; 53 } 54 }
書寫這篇隨筆的主要目的是自己溫習和防遺忘,本著分享的心態公開,如有不妥之處,還請指出,相互交流。