JIT--第一次--標記已--存根--調用--查找存根--執行機器碼程序員
C#和CIL的關係:數據庫
C#和N#都是CIL實現,可是彼此不能互通:跨域
C#和N#公開不分知足規範,咱們才能互通數據結構
CLS就是描述多語言互通的規範函數
內存分配:線程棧優化
堆Heap:this
一個程序運行時,該進程存放引用類型變量的一塊內存,全局惟一!只有一個堆spa
棧Stack:線程
數據結構,先進後出,線程棧,一個線程存放變量的內存(一個線程有一個)3d
值類型分配在棧上,好比結構、枚舉、int等
引用類型分配在堆上,好比類、接口、委託等
引用類型
一、調用new的時候,就會去棧上開闢內存,建立實例。這就是爲何在構造函數中跨域使用this
二、把實例的引用傳遞給構造函數
三、執行構造函數
四、返回引用
裝箱拆箱
int i=3; obect obj=i;//裝箱 int k=(int)obj;//拆箱
引用類型在哪裏?值類型在哪裏?
值類型的值,會隨着對象的位置存儲。引用類型的值,必定在堆裏面。值類型的長度是肯定的,引用類型的長度是不肯定的,只有堆才能放各類值。
下面有一個例子:
public class MyTest { private int x; public MyTest(int n) { this.x=n; } }
MyTest t=new MyTest(3);//引用類型
那麼,t.x 這個3,是存放在哪裏呢?是堆上仍是棧上?
===.》出如今堆裏面,由於值類型的屬性,會隨着對象的位置存儲
public struct ValuePoint// : System.ValueType 結構不能有父類,由於隱式繼承了ValueType { public int x; public ValuePoint(int x) { this.x = x; this.Text = "1234"; } public string Text;//堆仍是棧? }
struct是值類型,可是裏面的Text,是存放在堆仍是棧?答案是,對立面,由於引用類型的值,必定出如今堆裏面。
string字符串內存分配
string student = "bingle1"; string student2 = student; Console.WriteLine(student);//bingle1 Console.WriteLine(student2);//bingle1 student2 = "bingle2";//=new string(APP); Console.WriteLine(student);//bingle1 Console.WriteLine(student2);//bingle2 Console.ReadLine();
string student = "bingle1"; string student2 = "bingle2";//共享 student2 = "bingle1"; Console.WriteLine(object.ReferenceEquals(student, student2));//true
爲何是true?由於同一個變量,享元分配內存。爲何享元?節約內存。
student2 = "binglebingle";//等於從新開闢一塊內存叫「binglebingle」 new String("binglebingle") Console.WriteLine(student);//bingle1
仍是bingle1,爲何?由於字符串的不可變性。爲何字符串不能夠變,開闢新內存不浪費嗎?由於在堆上是連續拜訪的,若是有變化,會致使其餘變量所有移動,成本過高,還不如從新new一個。
string student3 = string.Format("bing{0}", "le"); Console.WriteLine(object.ReferenceEquals(student, student3));//false
爲何是false?沒有享元。分配地址,而後計算,才知道是"bingle"。
string student4 = "bing" + "le"; Console.WriteLine(object.ReferenceEquals(student, student4));//true //true 編譯器優化了,直接就是bingle
string halfStudent = "le"; string student5= "bing" + halfStudent; Console.WriteLine(object.ReferenceEquals(student, student5)); //false 也是先內存,再計算
東西放在站上速度快,可是值類型是不能繼承的,長度也有限。
垃圾回收---CLR提供GC,託管堆垃圾回收
一、什麼樣的對象須要垃圾回收?
託管資源+引用類型。線程棧的是不須要垃圾回收的,用完立馬就回收了。
二、託管資源和非託管資源
託管資源的就是CLR控制的,new的對象、string字符串。非託管就不是CLR控制的,數據庫鏈接、文件流、句柄、打印機鏈接。using(SqlConnection)//被C#封裝了管道了那個非託管的數據庫鏈接資源。只要手動釋放的,都是非託管的。
三、哪些對象的內存,能被GC回收?
對象訪問不到了,那就能夠被回收了。程序----入口----去找對象---創建對象圖----訪問不到的就是垃圾,就能夠回收了。
四、對象是如何分配在堆上的?
連續分配在堆上的,每次分配就先檢查空間夠不夠。
五、何時執行GC?
a、new對象的時候----臨界點
b、GC.Collection(),這個方法會強制GC
c、程序退出時會GC
a="123"
a=null
GC.Collect 能夠GC,可是頻繁GC是很差的,GC是全局的
項目中有6個小時才運行new一次,何時GC? 不GC,能夠手動GC
六、GC的過程是怎麼樣的?
N個對象,所有標機Wie垃圾,入口開始遍歷,訪問到的就標機能夠訪問(+1),遍歷完就清理內存,產生不連續的內存,壓縮,地址移動,修改變量指向,因此全局會阻塞。
清理內存分兩種狀況:
a、無析構函數,直接清理內存
b、把對象轉到一個單獨的隊列,會有一個析構函數專門作這個。一般在析構函數內部是用來作非託管資源釋放,由於CLR確定調用,因此避免使用者忘記的氣礦。
七、垃圾回收策略
對象分代:3代
0代:第一次分配到堆,就是0代
1代:經歷了一次GC,還存在的
2代:經歷了兩次或以上的GC,還存在的。
垃圾回收時,優先回收0代,提高小路,最多也最容器釋放。0代不夠,找1代,1代不夠找2代,再不夠就不用了。。。代的數值越大,越難回收。
大對象堆:一是內存移動大對象;二是0代空間問題。80000字節就叫大對象,沒有分代,直接都是2代。
那麼,靜態資源在程序退出的時候,會GC嗎?答案是,會的。(其實回收的不是變量,是某個對象所佔據的內存,若是存在一個對象,指向它的引用變量的數量爲0,那個GC會擇機回收它佔據的內存。應用程序域卸載的時候回收靜態變量。)
析構函數:被動清理;Dispose:主動清理
public class StandardDispose : IDisposable { //演示建立一個非託管資源 private string _UnmanageResource = "未被託管的資源"; //演示建立一個託管資源 private string _ManageResource = "託管的資源"; private bool _disposed = false; /// <summary> /// 實現IDisposable中的Dispose方法 /// </summary> public void Dispose() { this.Dispose(true); //必須爲true GC.SuppressFinalize(this);//通知垃圾回收機制再也不調用終結器(析構器) } /// <summary> /// 不是必要的,提供一個Close方法僅僅是爲了更符合其餘語言(如C++)的規範 /// </summary> public void Close() { this.Dispose(); } /// <summary> /// 必須,以備程序員忘記了顯式調用Dispose方法 /// </summary> ~StandardDispose() { //必須爲false this.Dispose(false); } /// <summary> /// 非密封類修飾用protected virtual /// 密封類修飾用private /// </summary> /// <param name="disposing"></param> protected virtual void Dispose(bool disposing) { if (this._disposed)//已經被釋放的還能夠不異常 { return; } if (disposing) { // 清理託管資源 if (this._ManageResource != null) { //Dispose this._ManageResource = null; } } // 清理非託管資源 if (this._UnmanageResource != null) { //Dispose conn.Dispose() this._UnmanageResource = null; } //讓類型知道本身已經被釋放 this._disposed = true; } public void PublicMethod() { if (this._disposed) { throw new ObjectDisposedException("StandardDispose", "StandardDispose is disposed"); } // }