ASP.NET堆和棧一之基本概念和值類型內存分配
".NET的堆和棧"系列:
ASP.NET堆和棧一之基本概念和值類型內存分配
ASP.NET堆和棧二之值類型和引用類型參數傳遞和內存分配
ASP.NET堆和棧三之引用類型對象拷貝和內存分配
ASP.NET堆和棧四之對托管和非托管資源垃圾的回收和內存分配
當我們對.NET Framework的一些基本面瞭解之後,實際上,還是很有必要瞭解一些更底層的知識。比如.NET Framework是如何進行內存管理的,是如何垃圾回收的……這樣,我們才能寫出更高性能的程序。
在.NET Framework中,有2個地方幫我們保存管理數據:一個是"堆",也叫"托管堆",由.NET Framework的垃圾收集器(Garbage Collection, GC)管理;另一個是"棧",也叫"線程堆棧",由操作系統直接管理。它們都寄宿在操作系統內存。
什麼是"棧"
可以把"棧"想像成由下而上堆疊起來的盒子,值類型實例存儲於此。
在應用程序中,每當調用一個方法,就相當於在"堆"上放上瞭一個盒子A,這時,應用程序隻能使用處在"棧"最上方、剛被放上的這個盒子A,當方法執行結束,相當於把最上方的盒子A扔掉。接下來,剛才還在A下面的盒子B就處在"棧"的最上方瞭,於是應用程序又開始使用盒子B,以此類推。而且,每當把最上面的盒子扔掉,其對應的內存也被自動釋放。
棧的優點是執行效率高,缺點是存儲容量有限。
在.NET Framework中,所有派生於System.ValueType的就是值類型,值類型實例位於"棧"。值類型包括:
- bool
- byte
- char
- decimal
- double
- enum
- float
- int
- long
- sbyte
- short
- stuct
- uint
- ulong
- short
什麼是"堆"
可以把"堆"想像成一些擺放無序的盒子,引用類型實例存儲於此。
我們可以在任何時候,使用任何盒子。我們需要借助垃圾收集器(Garbage Collection, GC)的自動回收機制或手動處理,以保證"堆"的盒子被及時回收。
另外,根據引用類型實例的大小,"堆"分為"GC堆"和"LOH(Large Object Heap)堆",當引用類型實例大小小於85000個字節的時候,實例被分配在"GC堆"上;當實例大小大於或等於於85000個字節的時候,實例被分配在"LOH(Large Object Heap)堆"。
在.NET Framework中,所有派生於System.Object的就是引用類型,引用類型實例位於"堆"。引用類型包括:
- 類 class
- 接口 interface
- 委托 delegate
- object
- string
值類型內存分配
在方法內的值類型內存分配
public int Add(int x) { int result; result = x + 2; return result; }
1、在執行Add(int x)方法之前,方法參數x被存放到"棧"的頂部。
2、在"method table"中搜尋Add()方法,如果找不到,就讓JIT及時編譯再存放到"method table"中去。
3、開始執行Add(int x)方法,局部變量result也需要"棧"中的一些內存。
4、當方法執行完畢,先釋放result,再釋放x,線程堆棧指針重新指向。
在引用類型內部的值類型內存分配
public class MyClass { public int MyValue; } public MyClass Add(int x) { MyClass result = new MyClass(); result.MyValue = x + 2; return result; }
1、在執行Add(int x)方法之前,方法參數x被存放到"棧"的頂部。
2、在"method table"中搜尋Add()方法,如果找不到,就讓JIT及時編譯再存放到"method table"中去。
3、開始執行Add(int x)方法,執行MyClass result = new MyClass()
先在托管堆上創建一個MyClass的實例,然後在棧上開辟一塊空間並指向實例地址。
4、當方法執行完畢,在棧中由上到下依次釋放內存。
此時,在托管堆上的MyClass實例如何處理呢?
5、此時,垃圾回收器登場瞭,他在托管堆中搜尋那些不再被引用的對象實例,然後實施回收。
練習題
public int ReturnValue() { int x = new int(); x = 3; int y = new int(); y = x; y = 4; return x; }
結果是:3, 因為值類型x變量,在方法執行結束之前,一直存在於棧上。
public int ReturnValue2() { MyInt x = new MyInt(); x.MyValue = 3; MyInt y = new MyInt(); y = x; y.MyValue = 4; return x.MyValue; }
結果是:4,因為,當通過y=x把x賦值給y時,實際上是把x在托管堆上的地址賦值y,也就是,棧上的x和y都指向托管堆上的同一個對象實例,改變y的字段值,相當於改變x的字段值。
以上就是這篇文章的全部內容瞭,希望本文的內容對大傢的學習或者工作具有一定的參考學習價值,謝謝大傢對WalkonNet的支持。如果你想瞭解更多相關內容請查看下面相關鏈接