1. 程式人生 > >C#內存分配

C#內存分配

在線 tps runtime 幫我 繼承 壓縮 占用 發生 div

博文帶著3個疑問學習:(整理的有錯誤,請大家幫我改正)

CLR它負責資源管理(內存分配和垃圾收集等),並保證應用和底層操作系統之間必要的分離

問題1CLR(Common Language Runtime 公共語言運行時)管理內存的三塊區域是什麽?

問題2:哪些操作會 創建對象和分配內存?

問題3:內存的分配機制?

  1. CLR管理內存的三塊區域
    註:內存——堆棧 堆(托管堆)

線程的堆棧:用於分配值類型的實例-有操作系統管理分配釋放內存。
GC堆(托管堆):用於分配引用類型的實例對象內存小於8500 byte的。當有內存分配時,垃圾回收器"可能"會對GC堆進行壓縮。
LOH堆(Large Object Heap

):用於分配引用類型的大對象實例(大於8500byte,不會被垃圾回收器壓縮,而且只在GC堆完全被回收時回收。

  1. 哪些操作會 創建對象和分配內存?
    IL指令:.net中間語言
    newobj:引用類型對象創建
    ldstr:string類型對象創建
    newarr:數組對象創建
    box:值類型轉換引用類型,值類型字段拷貝到托管堆上發生 內存分配

3.內存的分配機制
3.1 堆棧的內存分配機制
對於值類型:當作為類的值類型成員時,這個時候值類型將被分配在托管堆(堆)上。如:

class Car
{
    int carYear;
    string carName;
}

即:Car oneCar=new Car(); 這個

Car類的引用變量將被分配在線程堆棧上,而這個對象的成員,如:carYear,carName將被分配在堆上。

對於堆棧的變量來說,是由操作系統來分配和釋放內存的,操作系統維護著一個堆棧指針來指向一個自由空間(未被分配的內存的開始位)。堆棧的分配是從高位——>低位,而釋放是從低位——>高位,如:

static void Main()
{
    int i=1;
    char a=A;

}

分析:
分配
第一步:C#程序從Main函數開始,每個線程堆棧都有一個初始化地址,比如這個程序的初始化地址是100;
第二步:int類型占有4字節,那麽開始堆棧指針是在100這個位置,然後分配4字節給值為1的Int類型(100-97)保存,然後堆棧指針指向96.
第三步:char類型占有2字節,那麽堆棧指針由96指向94。
第三步:當運行到右括號的時候,將會釋放內存
釋放
第四步:釋放的步驟是分配的反方向,堆棧指針逐步向上移動。

註:上面的方式更可以說是“局部變量的分配機制”,因為這些值類型變量隨著方法的結束而結束,效率高,但是內存容量小。

3.2 堆(托管堆)的內存分配機制
對於引用類型:引用類型的變量的內存是分配在堆棧上的,而引用類型的對象實例的內存是分配在托管堆上的。
對於托管堆裏有2個重要的區域:GC堆和加載堆(Loader Heap)

 class Program
    {
        static void Main(string[] args)
        {
            B b =unll;
       b = new B(); b.fild1
= 11; A a = b; a.fild1 = 12; Console.WriteLine("B類型b對象的值為:{0}",b.fild1); Console.WriteLine("A類型a對象的值為:{0}", a.fild1); Console.ReadKey(); } } public class A { public int fild1; } public class B:A { public int fild2; }

回歸到我們上一個博客講解的內容:

  分配
    第一步:Main函數開始,聲明一個B類型變量,這只是一個引用,或者說是一個指針,它是存儲在堆棧上的,占有4個字節。這個時候,沒有指向對象,初始化為NULL。

    第二步:new對象,這個過程很復雜,因為IL(中間代碼)代碼為newobj,這個過程會一直向上查找其所有父類,直到Object類型,並且這個過程會計算類型和所有繼承關系類型的字段,並且返回一個總的占有字節數。

    第三步:分配內存對於堆棧是 先進後出,向低位擴展 ,分配內存是由上-下,釋放內存是由下-上。

      對於堆是 先進先出,向高位擴展。分配內存是由下-上,由GC回收器回收內存。

      對於引用類型,父類在前子類在後,當發現內存不足時,會啟動GC回收器,回收垃圾對象占用的內存。

    第四步:調用構造函數,進行初始化,完成創建對象過程

   註意:對於b對象的回收不是出了大括號就回收了對象而是等到GC回收器回收的對象

  在這裏就很好解釋為什麽我們輸出的a對象和b對象的值都為12.在我們的轉換的過程並沒有在堆中開辟新的內存空間。一直都是用的可以說是a對象的指針去改變堆中對象的值。

C#內存分配