CLRCore(CLR核心機制)


 

JIT--第一次--標記已--存根--調用--查找存根--執行機器碼

 

 

C#和CIL的關系:

 

 C#和N#都是CIL實現,但是彼此不能互通:

 

 C#和N#公開不分滿足規范,我們才能互通

 

 CLS就是描述多語言互通的規范

 

 

內存分配:線程棧

  堆Heap:

    一個程序運行時,該進程存放引用類型變量的一塊內存,全局唯一!只有一個堆

  棧Stack:

    數據結構,先進后出,線程棧,一個線程存放變量的內存(一個線程有一個)

  值類型分配在棧上,比如結構、枚舉、int等

  引用類型分配在堆上,比如類、接口、委托等

引用類型

  1、調用new的時候,就會去棧上開辟內存,創建實例。這就是為什么在構造函數中跨域使用this

  2、把實例的引用傳遞給構造函數

  3、執行構造函數

  4、返回引用

裝箱拆箱

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,托管堆垃圾回收

  1、什么樣的對象需要垃圾回收?

    托管資源+引用類型。線程棧的是不需要垃圾回收的,用完立馬就回收了。

  2、托管資源和非托管資源

    托管資源的就是CLR控制的,new的對象、string字符串。非托管就不是CLR控制的,數據庫連接、文件流、句柄、打印機連接。using(SqlConnection)//被C#封裝了管道了那個非托管的數據庫連接資源。只要手動釋放的,都是非托管的。

  3、哪些對象的內存,能被GC回收?

    對象訪問不到了,那就可以被回收了。程序----入口----去找對象---建立對象圖----訪問不到的就是垃圾,就可以回收了。

  4、對象是如何分配在堆上的?

    連續分配在堆上的,每次分配就先檢查空間夠不夠。

 

   5、什么時候執行GC?

    a、new對象的時候----臨界點

    b、GC.Collection(),這個方法會強制GC

    c、程序退出時會GC

    a="123"

    a=null

    GC.Collect 可以GC,但是頻繁GC是不好的,GC是全局的

    項目中有6個小時才運行new一次,什么時候GC? 不GC,可以手動GC

  6、GC的過程是怎么樣的?

    N個對象,全部標機Wie垃圾,入口開始遍歷,訪問到的就標機可以訪問(+1),遍歷完就清理內存,產生不連續的內存,壓縮,地址移動,修改變量指向,所以全局會阻塞。

    清理內存分兩種情況:

      a、無析構函數,直接清理內存

      b、把對象轉到一個單獨的隊列,會有一個析構函數專門做這個。通常在析構函數內部是用來做非托管資源釋放,因為CLR肯定調用,所以避免使用者忘記的氣礦。

  7、垃圾回收策略

 

     對象分代: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");
         }
         //
     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM