[譯].Net中的內存-什麼分配在了哪裏

原文連接:https://jonskeet.uk/csharp/memory.htmlhtml

  人們在理解值類型和引用類型之間的差別時由於「值類型在棧上分配,引用類型在堆上分配」這句話形成了不少混亂。這徹底是不對的,本文試圖澄清這個問題。優化

變量中有什麼?spa

  理解.NET中內存工做方式的關鍵是理解變量是什麼,以及它的值是什麼。在最基本的層面上,變量是變量名和內存之間的關聯。變量的值是與之關聯的內存中的內容。該值佔用內存空間的大小和值的解釋取決於變量的類型 - 這正是值類型和引用類型之間的差別所在。指針

  引用類型變量的值始終是引用或null。若是是引用,則它必須是與其變量類型兼容的對象的引用。例如,以Stream s聲明的變量s的值是null或Stream類型(或其兼容類型)實例的引用。引用類型變量所佔內存空間的大小是引用的大小,引用的大小在32位模式下固定爲4個字節,在64位模式下固定爲8個字節。code

  值類型變量的值始終是其對象自己的值。例如,對於給定的結構:htm

struct PairOfInts
{
    public  int a;
    public  int b;
}

   以PairOfInts pair聲明的變量pair的值是整數對自己,而不是對一對整數的引用。其所佔內存空間則是兩個整數的大小,即8個字節。請注意,值類型變量永遠不能賦值爲null - 由於這沒有任何意義,值類型變量不是一個引用。對象

那麼東西存放在哪裏?  blog

  變量的分配位置取決於聲明它的上下文:內存

  • 局部變量在棧上分配。這包括引用類型變量 - 變量自己位於棧上,其引用的值分配在堆上。方法參數也計爲局部變量,但若是使用ref、out、in修飾符修飾它們,則它們再也不是原始類型,而是轉換爲託管指針類型(Type &),此時傳遞的是原變量的指針,再也不是變量自己。
  • 引用類型的對象始終在堆上分配。
  • 值類型的對象始終內聯分配。即在方法中聲明的值類型變量在棧上分配,而做爲類的實例字段的值類型變量將在堆上分配。
  • 靜態變量在堆上分配,包括引用類型和值類型中聲明的靜態變量。不管建立多少個實例,靜態變量都共享一個內存空間。

  上述規則有幾個例外:在使用匿名方法時的外部變量和迭代器中的局部變量會由編譯器優化爲其它類型的實例字段,這些變量會轉移到堆中分配。字符串

舉個例子

  上述文字描述可能聽起來有點複雜,但一個完整的例子可讓事情更清楚一些:

using System;

struct PairOfInts
{
    static  int counter = 0;
    
    public  int a;
    public  int b;
    
    internal PairOfInts(int x, int y)
    {
        A = x;
        B = y;
        counter++;
    }
}

class Test
{
    PairOfInts pair;
    string name;
    
    Test(PairOfInts p, string s, int x)
    {
        pair = p;
        name = s;
        pair.a + = x;
    }
    
    static  void Main()
    {
        PairOfInts z = new PairOfInts(1, 2);
        Test t1 = new Test(z, "first", 1);
        Test t2 = new Test(z, "second", 2);
        Test t3 = null;
        Test t4 = t1;
        //XXX
    }
}

   讓咱們看一下標記「XXX」位置時內存中的內容。

  • 在棧上分配一個PairOfInts類型的對象,對應變量z。
  • 在堆上分配一個Test類型的對象,在棧上分配一個引用指向該對象,對應變量t1。以32位模式舉例,該對象在堆中佔用20個字節:8個字節的頭信息(全部堆對象都有),8個字節用於存儲PairOfInts實例,4個字節用於存儲字符串引用。
  • 在堆上分配一個Test類型的對象,在棧上分配一個引用指向該對象,對應變量t2。該對象與上面的對象很是類似。
  • 在棧上分配一個引用,對應變量t3。這個引用是null - 它沒有引用任何對象。
  • 在棧上分配一個引用,對應變量t4,並賦值t1引用的對象,此時t1和t4引用堆內存中的同一個對象。
  • 最後,在堆內存中有一個靜態變量PairOfInts.counter。

 


若是您以爲閱讀本文對您有幫助,請點一下「推薦」按鈕,您的承認是我寫做的最大動力!

做者:Minotauros
出處:https://www.cnblogs.com/minotauros/

本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。

相關文章
相關標籤/搜索