青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 195,  comments - 30,  trackbacks - 0

 

C#的內存管理:堆、棧、托管堆與指針

32位的Windows操作系統中,每個進程都可以使用4GB的內存,這得益于虛擬尋址技術,在這4GB的內存中存儲著可執行代碼、代碼加載的DLL和程序運行的所有變量,在C#中,虛擬內存中有個兩個存儲變量的區域,一個稱為堆棧,一個稱為托管堆,托管堆的出現是.net不同于其他語言的地方,堆棧存儲值類型數據,而托管堆存儲引用類型如類、對象,并受垃圾收集器的控制和管理。在堆棧中,一旦變量超出使用范圍,其使用的內存空間會被其他變量重新使用,這時其空間中存儲的值將被其他變量覆蓋而不復存在,但有時候我們希望這些值仍然存在,這就需要托管堆來實現。我們用幾段代碼來說明其工作原理,假設已經定義了一個類class1:

 

class1 object1;

 

object1=new class1();

 

第一句定義了一個class1的引用,實質上只是在堆棧中分配了一個4個字節的空間,它將用來存府后來實例化對象在托管堆中的地址,在windows中這需要4個字節來表示內存地址。第二句實例化object1對象,實際上是在托管堆中開僻了一個內存空間來存儲類class1的一個具體對象,假設這個對象需要36個字節,那么object1指向的實際上是在托管堆一個大小為36個字節的連續內存空間開始的地址。由此也可以看出在C#編譯器中為什么不允許使用未實例化的對象,因為這個對象在托管堆中還不存在。當對象不再使用時,這個被存儲在堆棧中的引用變量將被刪除,但是從上述機制可以看出,在托管堆中這個引用指向的對象仍然存在,其空間何時被釋放取決垃圾收集器而不是引用變量失去作用域時。

 

在使用電腦的過程中大家可能都有過這種經驗:電腦用久了以后程序運行會變得越來越慢,其中一個重要原因就是系統中存在大量內存碎片,就是因為程序反復在堆棧中創建和釋入變量,久而久之可用變量在內存中將不再是連續的內存空間,為了尋址這些變量也會增加系統開銷。在.net中這種情形將得到很大改善,這是因為有了垃圾收集器的工作,垃圾收集器將會壓縮托管堆的內存空間,保證可用變量在一個連續的內存空間內,同時將堆棧中引用變量中的地址改為新的地址,這將會帶來額外的系統開銷,但是,其帶來的好處將會抵消這種影響,而另外一個好處是,程序員將不再花上大量的心思在內在泄露問題上。

 

當然,C#程序中不僅僅只有引用類型的變量,仍然也存在值類型和其他托管堆不能管理的對象,如果文件名柄、網絡連接和數據庫連接,這些變量的釋放仍需要程序員通過析構函數或IDispose接口來做

 

另一方面,在某些時候C#程序也需要追求速度,比如對一個含用大量成員的數組的操作,如果仍使用傳統的類來操作,將不會得到很好的性能,因為數組在C#中實際是System.Array的實例,會存儲在托管堆中,這將會對運算造成大量的額外的操作,因為除了垃圾收集器除了會壓縮托管堆、更新引用地址、還會維護托管堆的信息列表。所幸的是C#中同樣能夠通過不安全代碼使用C++程序員通常喜歡的方式來編碼,在標記為unsafe的代碼塊使用指針,這和在C++中使用指針沒有什么不同,變量也是存府在堆棧中,在這種情況下聲明一個數組可以使用stackalloc語法,比如聲明一個存儲有50double類型的數組:

 

double* pDouble=stackalloc double[50]

 

stackalloc會給pDouble數組在堆棧中分配50double類型大小的內存空間,可以使用pDouble[0]*(pDouble+1)這種方式操作數組,與在C++中一樣,使用指針時必須知道自己在做什么,確保訪問的正確的內存空間,否則將會出現無法預料的錯誤。

 

掌握托管堆、堆棧、垃圾收集器和不安全代碼的工作原理和方式,將有助于你成為真正的優秀C#程序員。

 

進程中每個線程都有自己的堆棧,這是一段線程創建時保留下的地址區域。我們的棧內存即在此。至于內存,我個人認為在未用new定義時,堆應該就是未保留提交的自由空間,new的功能是在這些自由空間中保留(并提交?)出一個地址范圍

 

(Stack)是操作系統在建立某個進程時或者線程(在支持多線程的操作系統中是線程)為這個線程建立的存儲區域,該區域具有FIFO的特性,在編譯的時候可以指定需要的Stack的大小。在編程中,例如C/C++中,所有的局部變量都是從棧中分配內存空間,實際上也不是什么分配,只是從棧頂向上用就行,在退出函數的時候,只是修改棧指針就可以把棧中的內容銷毀,所以速度最快。  

 堆(Heap)是應用程序在運行的時候請求操作系統分配給自己內存,一般是申請/給予的過程,C/C++分別用malloc/New請求分配Heap,用free/delete銷毀內存。由于從操作系統管理的內存分配所以在分配和銷毀時都要占用時間,所以用堆的效率低的多!但是堆的好處是可以做的很大,C/C++對分配的Heap是不初始化的。  

 Java中除了簡單類型(int,char等)都是在堆中分配內存,這也是程序慢的一個主要原因。但是跟C/C++不同,Java中分配Heap內存是自動初始化的。在Java中所有的對象(包括intwrapper   Integer)都是在堆中分配的,但是這個對象的引用卻是在Stack中分配。也就是說在建立一個對象時從兩個地方都分配內存,在Heap中分配的內存實際建立這個對象,而在Stack中分配的內存只是一個指向這個堆對象的指針(引用)而已。

 

.NET的所有技術中,最具爭議的恐怕是垃圾收集(Garbage CollectionGC)了。作為.NET框架中一個重要的部分,托管堆和垃圾收集機制對我們中的大部分人來說是陌生的概念。在這篇文章中將要討論托管堆,和你將從中得到怎樣的好處。

  為什么要托管堆?

  .NET框架包含一個托管堆,所有的.NET語言在分配引用類型對象時都要使用它。像值類型這樣的輕量級對象始終分配在棧中,但是所有的類實例和數組都被生成在一個內存池中,這個內存池就是托管堆。

  垃圾收集器的基本算法很簡單:

  將所有的托管內存標記為垃圾

  尋找正被使用的內存塊,并將他們標記為有效

  釋放所有沒有被使用的內存塊

  整理堆以減少碎片

  托管堆優化

  看上去似乎很簡單,但是垃圾收集器實際采用的步驟和堆管理系統的其他部分并非微不足道,其中常常涉及為提高性能而作的優化設計。舉例來說,垃圾收集遍歷整個內存池具有很高的開銷。然而,研究表明大部分在托管堆上分配的對象只有很短的生存期,因此堆被分成三個段,稱作generations。新分配的對象被放在generation 0中。這個generation是最先被回收的——在這個generation中最有可能找到不再使用的內存,由于它的尺寸很小(小到足以放進處理器的L2 cache中),因此在它里面的回收將是最快和最高效的。

  托管堆的另外一種優化操作與locality of reference規則有關。該規則表明,一起分配的對象經常被一起使用。如果對象們在堆中位置很緊湊的話,高速緩存的性能將會得到提高。由于托管堆的天性,對象們總是被分配在連續的地址上,托管堆總是保持緊湊,結果使得對象們始終彼此靠近,永遠不會分得很遠。這一點與標準堆提供的非托管代碼形成了鮮明的對比,在標準堆中,堆很容易變成碎片,而且一起分配的對象經常分得很遠。

  還有一種優化是與大對象有關的。通常,大對象具有很長的生存期。當一個大對象在.NET托管堆中產生時,它被分配在堆的一個特殊部分中,這部分堆永遠不會被整理。因為移動大對象所帶來的開銷超過了整理這部分堆所能提高的性能。

  關于外部資源(External Resources)的問題

  垃圾收集器能夠有效地管理從托管堆中釋放的資源,但是資源回收操作只有在內存緊張而觸發一個回收動作時才執行。那么,類是怎樣來管理像數據庫連接或者窗口句柄這樣有限的資源的呢?等待,直到垃圾回收被觸發之后再清理數據庫連接或者文件句柄并不是一個好方法,這會嚴重降低系統的性能。

  所有擁有外部資源的類,在這些資源已經不再用到的時候,都應當執行Close或者Dispose方法。從Beta2(譯注:本文中所有的Beta2均是指.NET Framework Beta2,不再特別注明)開始,Dispose模式通過IDisposable接口來實現。這將在本文的后續部分討論。

  需要清理外部資源的類還應當實現一個終止操作(finalizer)。在C#中,創建終止操作的首選方式是在析構函數中實現,而在Framework層,終止操作的實現則是通過重載System.Object.Finalize 方法。以下兩種實現終止操作的方法是等效的:

  ~OverdueBookLocator()

  {

   Dispose(false);

  }

  和:

  public void Finalize()

  {

   base.Finalize();

   Dispose(false);

  }

  在C#中,同時在Finalize方法和析構函數實現終止操作將會導致錯誤的產生。

  除非你有足夠的理由,否則你不應該創建析構函數或者Finalize方法。終止操作會降低系統的性能,并且增加執行期的內存開銷。同時,由于終止操作被執行的方式,你并不能保證何時一個終止操作會被執行。

  內存分配和垃圾回收的細節

  對GC有了一個總體印象之后,讓我們來討論關于托管堆中的分配與回收工作的細節。托管堆看起來與我們已經熟悉的C++編程中的傳統的堆一點都不像。在傳統的堆中,數據結構習慣于使用大塊的空閑內存。在其中查找特定大小的內存塊是一件很耗時的工作,尤其是當內存中充滿碎片的時候。與此不同,在托管堆中,內存被組制成連續的數組,指針總是巡著已經被使用的內存和未被使用的內存之間的邊界移動。當內存被分配的時候,指針只是簡單地遞增——由此而來的一個好處是,分配操作的效率得到了很大的提升。

  當對象被分配的時候,它們一開始被放在generation 0中。當generation 0的大小快要達到它的上限的時候,一個只在generation 0中執行的回收操作被觸發。由于generation 0的大小很小,因此這將是一個非常快的GC過程。這個GC過程的結果是將generation 0徹底的刷新了一遍。不再使用的對象被釋放,確實正被使用的對象被整理并移入generation 1中。

  當generation 1的大小隨著從generation 0中移入的對象數量的增加而接近它的上限的時候,一個回收動作被觸發來在generation 0generation 1中執行GC過程。如同在generation 0中一樣,不再使用的對象被釋放,正在被使用的對象被整理并移入下一個generation中。大部分GC過程的主要目標是generation 0,因為在generation 0中最有可能存在大量的已不再使用的臨時對象。對generation 2的回收過程具有很高的開銷,并且此過程只有在generation 0generation 1GC過程不能釋放足夠的內存時才會被觸發。如果對generation 2GC過程仍然不能釋放足夠的內存,那么系統就會拋出OutOfMemoryException異常

  帶有終止操作的對象的垃圾收集過程要稍微復雜一些。當一個帶有終止操作的對象被標記為垃圾時,它并不會被立即釋放。相反,它會被放置在一個終止隊列(finalization queue)中,此隊列為這個對象建立一個引用,來避免這個對象被回收。后臺線程為隊列中的每個對象執行它們各自的終止操作,并且將已經執行過終止操作的對象從終止隊列中刪除。只有那些已經執行過終止操作的對象才會在下一次垃圾回收過程中被從內存中刪除。這樣做的一個后果是,等待被終止的對象有可能在它被清除之前,被移入更高一級的generation中,從而增加它被清除的延遲時間。

  需要執行終止操作的對象應當實現IDisposable接口,以便客戶程序通過此接口快速執行終止動作。IDisposable接口包含一個方法——Dispose。這個被Beta2引入的接口,采用一種在Beta2之前就已經被廣泛使用的模式實現。從本質上講,一個需要終止操作的對象暴露出Dispose方法。這個方法被用來釋放外部資源并抑制終止操作,就象下面這個程序片斷所演示的那樣:

  public class OverdueBookLocator: IDisposable

  {

   ~OverdueBookLocator()

   {

   InternalDispose(false);

   }

   public void Dispose()

   {

   InternalDispose(true);

   }

   protected void InternalDispose(bool disposing)

   {

   if(disposing)

   {

   GC.SuppressFinalize(this);

   // Dispose of managed objects if disposing.

   }

   // free external resources here

   }

  }

 

這些都是.NETCLR的概念,和C#沒多大關系。

使用基于CLR的語言編譯器開發的代碼稱為托管代碼。

托管堆是CLR中自動內存管理的基礎。初始化新進程時,運行時會為進程保留一個連續的地址空間區域。這個保留的地址空間被稱為托管堆。托管堆維護著一個指針,用它指向將在堆中分配的下一個對象的地址。最初,該指針設置為指向托管堆的基址。

認真看MSDN Library,就會搞清楚這些概念。

 

以下代碼說明的很形象:

 

//引用類型('class' 類類型)

class SomeRef { public int32 x;}

 

//值類型('struct')

struct SomeVal(pulic Int32 x;}

 

static void ValueTypeDemo()

{

 SomeRef r1=new SomeRef();//分配在托管堆

 SomeVal v1=new SomeVal();//堆棧上

 r1.x=5;//解析指針

 v1.x=5;//在堆棧上修改

 

 SomeRef r2=r1;//僅拷貝引用(指針)

 SomeVal v2=v1;//先在堆棧上分配,然后拷貝成員

 

 r1.x=8;//改變了r1,r2的值

 v1.x=9;//改變了v1,沒有改變v2

}

posted on 2011-04-08 15:10 luis 閱讀(567) 評論(0)  編輯 收藏 引用

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


<2012年4月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

常用鏈接

留言簿(3)

隨筆分類

隨筆檔案

文章分類

文章檔案

友情鏈接

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产日韩精品| 午夜在线不卡| 欧美日韩一区二区视频在线| 你懂的视频一区二区| 久久综合给合| 欧美α欧美αv大片| 欧美激情一区二区三区在线| 欧美精品在线看| 国产精品扒开腿爽爽爽视频| 国产啪精品视频| 一区二区三区在线免费视频| 黄页网站一区| 日韩亚洲欧美一区二区三区| 一本色道久久88综合亚洲精品ⅰ| 亚洲一区二区三区色| 国产欧美日韩麻豆91| 国产精品久久综合| 激情视频一区二区三区| 亚洲免费观看高清完整版在线观看熊 | 国产一区二区三区久久久| 国内精品一区二区三区| 亚洲国产另类 国产精品国产免费| 中文av一区特黄| 久久久国产精品一区二区中文| 美女网站久久| 亚洲色图自拍| 久久久久久久网| 欧美日韩小视频| 韩日午夜在线资源一区二区| 亚洲免费高清| 久久久综合精品| 99国产精品99久久久久久| 欧美在线免费观看| 国产精品magnet| 亚洲国产小视频在线观看| 性感少妇一区| 99视频有精品| 欧美国产日本在线| 国产一区二区三区观看| 在线亚洲激情| 亚洲国产高清高潮精品美女| 一区二区三区四区国产| 欧美激情精品久久久久久黑人 | 欧美精品www| 亚洲电影激情视频网站| 亚洲一区欧美二区| 欧美激情在线播放| 亚洲激情av| 久久这里只有| 午夜精品一区二区三区在线视 | 亚洲欧洲一区二区三区在线观看| 亚洲欧美日韩国产综合在线 | 亚洲男人的天堂在线aⅴ视频| 欧美成人日本| 久久精品中文字幕免费mv| 国产精品成人一区| 中国成人亚色综合网站| 亚洲国产你懂的| 欧美在线免费观看| 国模叶桐国产精品一区| 久久久久88色偷偷免费| 亚洲在线电影| 国产精品女同互慰在线看| 这里只有精品在线播放| 日韩视频中午一区| 欧美日韩亚洲视频| 亚洲综合大片69999| 一区二区三区精品视频| 国产精品久线观看视频| 久久精品国产第一区二区三区最新章节 | 香蕉av777xxx色综合一区| 9i看片成人免费高清| 国产色产综合色产在线视频| 国产一区二区三区视频在线观看| 欧美在线视频免费观看| 久久超碰97人人做人人爱| 狠狠入ady亚洲精品经典电影| 老司机午夜精品视频| 久久综合九色综合欧美狠狠| 亚洲狼人综合| 亚洲图片你懂的| 韩国美女久久| 亚洲人成网站999久久久综合| 欧美日韩中文在线| 性欧美超级视频| 久久久青草婷婷精品综合日韩| 亚洲免费av片| 亚洲综合久久久久| 在线看不卡av| 一片黄亚洲嫩模| 一区二区视频在线观看| 亚洲久久一区二区| 国产毛片精品视频| 亚洲国产精品999| 国产精品家教| 欧美 日韩 国产精品免费观看| 欧美日韩国产999| 久久久久9999亚洲精品| 欧美精品一区二区视频| 欧美伊人久久大香线蕉综合69| 麻豆精品传媒视频| 性色av一区二区三区红粉影视| 久久先锋影音av| 亚洲欧美中文日韩在线| 欧美成人国产一区二区| 欧美一区深夜视频| 欧美国产欧美亚洲国产日韩mv天天看完整 | 99精品国产99久久久久久福利| 亚洲天堂av综合网| 亚洲精品激情| 欧美亚洲一区| 99国产精品自拍| 欧美中文在线字幕| 亚洲欧美清纯在线制服| 欧美大片免费观看| 久久不射电影网| 久久精品视频在线播放| 亚洲欧美一区二区视频| 欧美精品 日韩| 欧美高清在线| 国语精品中文字幕| 亚洲欧美日韩精品久久| 亚洲欧美高清| 欧美日韩少妇| 日韩视频国产视频| 亚洲免费播放| 欧美激情综合在线| 亚洲国产一区二区a毛片| 在线成人性视频| 久久噜噜噜精品国产亚洲综合 | 亚洲黄色免费| 久久精品免视看| 亚洲欧美制服中文字幕| 另类亚洲自拍| 久久丁香综合五月国产三级网站| 欧美成年人网| 久久久久www| 欧美日韩综合在线| 久久全球大尺度高清视频| 欧美日韩中文字幕在线| 另类春色校园亚洲| 国产精品自在在线| 亚洲精品久久久久久下一站| 狠狠久久五月精品中文字幕| 亚洲一区二区久久| 亚洲一区国产| 免费久久99精品国产| 欧美激情在线免费观看| 国内精品亚洲| 欧美99在线视频观看| 亚洲精品视频一区| 性视频1819p久久| 国产中文一区| 免费人成网站在线观看欧美高清| 一本久久知道综合久久| 久久精彩视频| 久久婷婷激情| 91久久线看在观草草青青| 欧美精品久久久久久久久久| 91久久久久久| 午夜精品美女自拍福到在线| 国产精品一区在线观看你懂的| 亚洲人成免费| 亚洲一区观看| 国产在线高清精品| 久久青草欧美一区二区三区| 亚洲人成高清| 亚洲在线观看免费视频| 国产精品日日摸夜夜摸av| 小嫩嫩精品导航| 亚洲电影免费观看高清完整版在线| 亚洲美女色禁图| 国产精品久久久久aaaa樱花| 久久成人免费网| 亚洲靠逼com| 久久亚洲精品伦理| 亚洲一区日韩| 在线观看欧美精品| 国产精品对白刺激久久久| 久久精品亚洲一区| 一区二区三区导航| 欧美成人黑人xx视频免费观看| 亚洲最黄网站| 激情综合久久| 欧美亚男人的天堂| 免费观看亚洲视频大全| 亚洲欧美影院| 日韩视频在线永久播放| 欧美搞黄网站| 久久精品一区| 午夜一区二区三区在线观看| 亚洲免费观看高清完整版在线观看熊 | 亚洲国产日韩一级| 久久精品盗摄| 亚洲在线成人| 一本色道久久综合狠狠躁篇的优点| 国产一区二区三区精品久久久 | 久热精品视频| 香蕉久久夜色精品国产| 正在播放亚洲一区|