none
C# 變數消耗記憶體 RRS feed

  • 問題

  • 我想請問三個關於記憶體消耗的問題

    問題1.    

    int sum=0;
    void A()
    {
    int test=0;
    for(int i=1;i<101;i++)

    {
    test=i;
    sum+=test;
    }
    }

    int sum=0;

    void B()
    {
    for(int i=1;i<101;i++)

    {
    int test=i;
    sum+=test;
    }
    }

    請問一下這兩個function(A跟B)的test一個宣告在迴宣裡 一個宣告在迴圈外這樣使用的記憶體消耗哪個比較多,還是一樣?

    問題2.

    class ListClass()

    {

    public static List<int> TestList;

    }

    int sum=0;

    void A()

    {

    for(int i=0;i<ListClass.TestList.Count;i++)

    {

    sum+=ListClass.TestList[i];

    }

    }

    int sum=0;

    void B()

    {

    List<int> list=ListClass.TestList;

    for(int i=0;i<list.count.Count;i++)

    {

    sum+=list[i];

    }

    }

    這兩個function(A跟B)的記憶體消耗有不一樣嗎,如果有哪個消耗比較多? 然後CPU消耗會有不一樣嗎?

    問題3.

    class Test()

    {

    public int a;

    public static int b;

    }

    變數宣告成靜態跟動態在記憶體消耗上是,靜態宣告時就已經佔用記憶體,動態要new出來才算暫用記憶體,所以new兩個Test時占用兩個a但是不管new幾個Test都只暫用一個b的記憶體是這樣嗎?

    謝謝

    2015年12月30日 上午 04:08

解答

  • (1)

    問題1 和 問題2 大概看最佳化後的 IL Code 會比較準.

    如果沒有最佳化, 在(1) 的 void B() 方法內會產生較多的變數, 不過 100 個迴圈實在多不到哪去, 在(2) 的 void B() 方法內會多出一個變數.

    區域變數(也就是宣告在方法內的變數) 隨著方法的結束就會從 stack 裡被 pop 出來.

    (2)

    關於問題3, 你需要知道幾個基本知識.

    每個型別本身會是一個物件, 這種特殊的物件被稱之為 "型別物件(Type Object)" , 經由型別定義產生的個體(也就是通過所謂 new) 所產生的通常被稱之為 "執行個體 (Instance) " 或 狹義的"物件 (object) ". 事實上 Type Object 即是 Type Class 所產生的 Instance , 只是我們不用 Instance 稱呼 Type Object, 以便容易定義型別物件和一般物件的不同.

    型別中的靜態欄位, 是要你用到這個型別物件的時候才會被產生, 然後它的生命週期會隨著 Application Domain 結束. 所以靜態欄位基本上是跟著型別物件的. 由於型別物件在CLR 中只會被產生一次, 這也就是為什麼大多數人會說靜態的欄位只會被產生一次的道理.
    而執行個體的欄位是跟著執行個體的, 也就是當一個執行個體被產生的時候就會為這個欄位的變數留下一份記憶體.

    變數不一定等於物件, 參考型別和實值型別在這個方面有差異.

    (3)

    對 CLR 的記憶體來講, 除非是很大型的迴圈或是遞迴, 否則區域變數要能夠到達 stack overflow 的地步並不容易. 我們真正在意的是參考型別的執行個體所佔用的記憶體, 所謂的"GC (垃圾收集)" 機制在處理的其實是這一塊, 而非處理變數.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    • 已標示為解答 Scozirge 2015年12月30日 下午 07:08
    2015年12月30日 下午 03:03
    版主

所有回覆

  • 實際變數佔用量會受到工具最佳化功能的影響, 所以要知道記憶體消耗量, 可以善用[效能及診斷]功能, 請參考:Performance and Diagnostics Hub in Visual Studio 2013

    2015年12月30日 上午 07:12
  • (1)

    問題1 和 問題2 大概看最佳化後的 IL Code 會比較準.

    如果沒有最佳化, 在(1) 的 void B() 方法內會產生較多的變數, 不過 100 個迴圈實在多不到哪去, 在(2) 的 void B() 方法內會多出一個變數.

    區域變數(也就是宣告在方法內的變數) 隨著方法的結束就會從 stack 裡被 pop 出來.

    (2)

    關於問題3, 你需要知道幾個基本知識.

    每個型別本身會是一個物件, 這種特殊的物件被稱之為 "型別物件(Type Object)" , 經由型別定義產生的個體(也就是通過所謂 new) 所產生的通常被稱之為 "執行個體 (Instance) " 或 狹義的"物件 (object) ". 事實上 Type Object 即是 Type Class 所產生的 Instance , 只是我們不用 Instance 稱呼 Type Object, 以便容易定義型別物件和一般物件的不同.

    型別中的靜態欄位, 是要你用到這個型別物件的時候才會被產生, 然後它的生命週期會隨著 Application Domain 結束. 所以靜態欄位基本上是跟著型別物件的. 由於型別物件在CLR 中只會被產生一次, 這也就是為什麼大多數人會說靜態的欄位只會被產生一次的道理.
    而執行個體的欄位是跟著執行個體的, 也就是當一個執行個體被產生的時候就會為這個欄位的變數留下一份記憶體.

    變數不一定等於物件, 參考型別和實值型別在這個方面有差異.

    (3)

    對 CLR 的記憶體來講, 除非是很大型的迴圈或是遞迴, 否則區域變數要能夠到達 stack overflow 的地步並不容易. 我們真正在意的是參考型別的執行個體所佔用的記憶體, 所謂的"GC (垃圾收集)" 機制在處理的其實是這一塊, 而非處理變數.


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    • 已標示為解答 Scozirge 2015年12月30日 下午 07:08
    2015年12月30日 下午 03:03
    版主