程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> .NET的堆和棧01,基本概念、值類型內存分配,.net01

.NET的堆和棧01,基本概念、值類型內存分配,.net01

編輯:C#入門知識

.NET的堆和棧01,基本概念、值類型內存分配,.net01


當我們對.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的字段值。

 

參考資料:
C# Heap(ing) Vs Stack(ing) in .NET: Part I
《你必須知道的.NET(第2版)》,作者王濤。


那個堆與棧在內存中怎表現的

Java把內存分成兩種,一種叫做棧內存,一種叫做堆內存 在函數中定義的一些基本類型的變量和對象的引用變量都是在函數的棧內存中分配。當在一段代碼塊中定義一個變量時,java就在棧中為這個變量分配內存空間,當超過變量的作用域後,java會自動釋放掉為改變量分配的內存空間,該內存空間可以立刻被另作他用。 堆內存用於存放由new創建的對象和數組。在堆中分配的內存,由java虛擬機自動垃圾回收器來管理。在堆中產生了一個數組或者對象後,還可以在棧中定義一個特殊的變量,這個變量的取值等於數組或者對象在堆內存中的首地址,在棧中的這個特殊的變量就變成了數組或者對象的引用變量,以後就可以在程序中使用棧內存中的引用變量來訪問堆中的數組或者對象,引用變量相當於為數組或者對象起的一個別名,或者代號。 引用變量是普通變量,定義時在棧中分配內存,引用變量在程序運行到作用域外釋放。而數組&對象本身在堆中分配,即使程序運行到使用new產生數組和對象的語句所在地代碼塊之外,數組和對象本身占用的堆內存也不會被釋放,數組和對象在沒有引用變量指向它的時候,才變成垃圾,不能再被使用,但是仍然占著內存,在隨後的一個不確定的時間被垃圾回收器釋放掉。這個也是java比較占內存的主要原因。但是在寫程序的時候,可以人為的控制。

如果幫助到您,請記得采納為滿意答案哈,謝謝!祝您生活愉快! vae.la
 

堆與棧在內存中的不同

都是內存塊,使用的方法不一樣。比如C語言中,棧是一種數據結構,特點是先進先出,需要你自己去建立;而堆內存直接用malloc去申請,用於動態內存分配。每種語言堆和棧的建立方法可能不一樣,但是用途差不多。再比如,win32匯編裡邊,棧內存都不用你自己申請的,系統會自動分配一個棧段,你只要用push和pop去使用棧就行了,而堆內存還得自己申請。
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved