1. 程式人生 > >淺談CLR的記憶體分配和回收機制

淺談CLR的記憶體分配和回收機制

相對於C++程式設計師來說,C#程式設計師是非常幸運的,至少我們不需要為記憶體洩漏(Memory Leak)而頭疼,不需要負責記憶體的分配和回收。但這不意味著我們只需要知道new的語法就可以了,作為一個嚴肅的C#程式設計師,我們應該對此有所瞭解,有助於我們編寫效能更好的程式碼。

主要內容:

CLR的記憶體分配機制

CLR的回收機制

一、CLR的記憶體分配機制

.NET Framework 的垃圾回收器管理應用程式的記憶體分配和釋放。每次使用 new 運算子建立物件時,執行庫都從託管堆為該物件分配記憶體。只要託管堆中有地址空間可用,執行庫就會繼續為新物件分配空間。

... object obj
=newobject(); ...

但是,記憶體不是無限大的。

publicvoid FillMemory() { ArrayList memory =new ArrayList();     // 輸出填充前所佔記憶體大小 Console.WriteLine("used memory:"+ GC.GetTotalMemory(false)); for (int i =0; i <100000; i++) { memory.Add(newobject()); }     // 輸出填充後所佔的記憶體大小 Console.WriteLine(
"used memory:"+ GC.GetTotalMemory(false)); }

最終,垃圾回收器必須執行回收以釋放一些記憶體。垃圾回收器優化引擎根據正在進行的分配情況確定執行回收的最佳時間。當垃圾回收器執行回收時,它檢查託管堆中不再被應用程式使用的物件並執行必要的操作來回收它們佔用的記憶體。

二、CLR的記憶體回收機制

一般我們在程式中建立的物件大部分都是託管物件,可依靠GC自動進行記憶體的回收,但是對於封裝了非託管資源的物件,就需要我們顯式過載object.Finalize()介面來實現非託管資源的釋放。

using System; using System.IO; public
class Foo { private SomeComObject _com; public Foo() { _com =new SomeComObject(); } // some other operation here...~Foo() { // release the unmanaged resource _com.Close(); } }

* 解構函式會在編譯時會被翻譯為protected void Finalize(),這是C#的解構函式的語法

GC在回收物件之前會呼叫Finalize()來實現非託管資源的釋放,不過按照MSDN的說法,Finalize()會導致效能的降低。

“垃圾回收器使用名為“終止佇列”的內部結構跟蹤具有 Finalize 方法的物件。每次您的應用程式建立具有 Finalize 方法的物件時,垃圾回收器都在終止佇列中放置一個指向該物件的項。託管堆中所有需要在垃圾回收器回收其記憶體之前呼叫它們的終止程式碼的物件都在終止佇列中含有項。

實現 Finalize 方法或解構函式對效能可能會有負面影響,因此應避免不必要地使用它們。用 Finalize 方法回收物件使用的記憶體需要至少兩次垃圾回收。當垃圾回收器執行回收時,它只回收沒有終結器的不可訪問物件的記憶體。這時,它不能回收具有終結器的不可訪問物件。它改為將這些物件的項從終止佇列中移除並將它們放置在標為準備終止的物件列表中。該列表中的項指向託管堆中準備被呼叫其終止程式碼的物件。垃圾回收器為此列表中的物件呼叫 Finalize 方法,然後,將這些項從列表中移除。後來的垃圾回收將確定終止的物件確實是垃圾,因為標為準備終止物件的列表中的項不再指向它們。在後來的垃圾回收中,實際上回收了物件的記憶體。” --[MSDN]

更加建議實現Sytem.IDisposable.Dispose()介面,用來實現對非託管資源的釋放,這也是.Net Framework中常見的設計模式。那該怎麼實現Dispose呢?

1、首先,Dispose介面應該釋放自身物件所佔用的資源,還應該呼叫基類的Dispose方法,釋放基類部分所佔用的資源。

publicvoid Dispose() { // do something to release my unmanaged resource ReleaseMyResource(); base.Dispose(); }

2、前面說過Finalize()會導致效能問題,那麼在執行Dispose以後就應該告訴GC不用在呼叫Finalize()了

publicvoid Dispose() { // do something to release my unmanaged resource ReleaseMyResource(); base.Dispose(); // tell gc not to call Finalize() GC.SuppressFinalize(this); }

當然我們完全可以定義一個MySpace.IClosable.Close(),通過實現這個介面來進行非託管資源的釋放,不過這實在沒有必要。

相關推薦

CLR記憶體分配回收機制

相對於C++程式設計師來說,C#程式設計師是非常幸運的,至少我們不需要為記憶體洩漏(Memory Leak)而頭疼,不需要負責記憶體的分配和回收。但這不意味著我們只需要知道new的語法就可以了,作為一個嚴肅的C#程式設計師,我們應該對此有所瞭解,有助於我們編寫效能更好的程式碼。 主要內容: CLR的記憶體分

Java 記憶體分配回收機制

Java的GC機制是自動進行的,和c語言有些區別需要程式設計師自己保證記憶體的使用和回收。 Java的記憶體分配和回收也主要在Java的堆上進行的,Java的堆中儲存了大量的物件例項,所以Java的堆也叫GC堆。 Java在垃圾收集的過程中,主要用到了分代收集演算法,

Java虛擬機器原理、記憶體分配回收機制

通常情況下Java編譯過的程式碼是一些class檔案,Java虛擬機器在執行程式碼的時候,首先解析Class,查詢該類的方法、常量,這些對於常規情況下都編譯成二進位制的程式碼儲存在jar檔案中,而對於Java的反射,VM的類載入器需要動態的查詢這些類名,雖然節省了編譯時間,但是執行時的查詢大大降低執行效率。

自動記憶體管理機制(4)- 記憶體分配回收策略

自動記憶體管理機制(4)- 記憶體分配和回收策略 Java所承諾的自動記憶體管理主要是針對物件記憶體的回收和物件記憶體的分配。 在Java虛擬機器的五塊記憶體空間中,程式計數器、Java虛擬機器棧、本地方法棧記憶體的分配和回收都具有確定性,一般在編譯階段就能確定需要分配的記憶體大小,

JVM記憶體分配

JVM 記憶體分配   由於Java程式是交由JVM執行的,所以我們在談Java記憶體區域劃分的時候事實上是指JVM記憶體區域劃分。如下是具體java程式的執行過程:  首先Java原始碼檔案(.java字尾)會被Java編譯器編譯為位元組碼檔案(.class字尾),然後由JVM中的類

最簡單例子圖解JVM記憶體分配回收

一、簡介 JVM採用分代垃圾回收。在JVM的記憶體空間中把堆空間分為年老代和年輕代。將大量(據說是90%以上)建立了沒多久就會消亡的物件儲存在年輕代,而年老代中存放生命週期長久的例項物件。年輕代中又被分為Eden區(聖經中的伊甸園)、和兩個Survivor區。新的物件分配是首先放在Eden區

GC發生時記憶體分配回收策略

在《深入理解java虛擬機器》一書中讀到3.6章節,記憶體分配和回收策略: 預備知識 java堆=年輕代(Eden+Survivor+Survivor)+老年代 Eden:Survivor:Survivor預設比例8:1:1,每次年輕代使用率90%(Ede

記憶體分配回收策略簡述

物件優先在Eden分配 大多數情況下,物件在新生代Eden區中分配。當Eden區沒有足夠空間進行分配時,虛擬機器將發起一次Minor GC。 新生代GC(Minor GC):指發生在新生代的垃圾收集動作,因為Java物件大多都具備朝生夕滅的特性,所以Minor GC非常頻繁

C++ 記憶體分配回收 (new delete)

“new”是C++的一個關鍵字,同時也是操作符。對於new的內容總結。 1、new的過程 當我們使用關鍵字new在堆上動態建立一個物件時,它實際上做了三件事:獲得一塊記憶體空間、呼叫建構函式、返回正確的指標。當然,如果我們建立的是簡單型別的變數,那麼第二步會被省略。假如我們

java記憶體分配

直接入正題,看看一下幾個例子,注意比較分析和理解:String a = “a1″;   String b = “a” + 1;   System.out.println((a == b)); //result = true  String a = “atrue”;   String b = “a” + “tr

記憶體分配回收策略

         在發生Minor GC之前,虛擬機器會先檢查老年代最大可用的連續空間是否大於新生代所有物件總空間,如果這個條件成立,那麼Minor GC可以確保是安全的。 如果不成立,則虛擬機器會檢視HandlePromotionFailure設定值是否允許擔保失敗。 如果允許,那麼會繼續檢查老年代最大可

Java虛擬機器堆的記憶體分配回收

java記憶體分配和回收,主要就是指java堆的記憶體分配和回收。java堆一般分為2個大的區域,一塊是新生代,一塊是老年代。在新生代中又劃分了3塊區域,一塊eden區域,兩塊surviver區域。一般稱為from surviver和to surviver。這些區域的大小可

java記憶體分配回收策略

一、導論   java技術體系中所提到的記憶體自動化管理歸根結底就是記憶體的分配與回收兩個問題,之前已經和大家談過java回收的相關知識,今天來和大家聊聊java物件的在記憶體中的分配。通俗的講,物件的記憶體分配就是在堆上的分配,物件主要分配在新生代的Eden上(關於物件在

C記憶體分配2

記憶體分配方式有三種: (1) 從靜態儲存區域分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的 整個執行期間都存在。例如全域性變數,static 變數。 (2) 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函 數執行結束時這些儲

Java記憶體分配策略

Java 記憶體分配策略 Java 程式執行時的記憶體分配策略有三種,分別是靜態分配,棧式分配,和堆式分配,對應的,三種儲存策略使用的記憶體空間主要分別是靜態儲存區(也稱方法區)、棧區和堆區。 靜態儲存區(方法區):主要存放靜態資料、全域性 static 資料和常量。這

C記憶體分配1

關於C語言記憶體方面的話題要真說起來的話那恐怕就沒頭了,所以本文僅僅是一個淺談。 關於記憶體問題不同平臺之間有一定的區別。本文所指的平臺是x86的Linux平臺 用C語言做程式(其實其他語言也一樣),不僅要熟悉語法,其實很多相關的背景知識也很重要。在學習和研究C語言中記憶體

簡述Java記憶體分配回收策略以及Minor GC Major GC(Full GC)

記憶體分配: 1. 棧區:棧可分為Java虛擬機器和本地方法棧 2. 堆區:堆被所有執行緒共享,在虛擬機器啟動時建立,是唯一的

java內存分配回收策略

內存空間 高效率 cde map details 閾值 老年代 total 關於 一、導論   java技術體系中所提到的內存自動化管理歸根結底就是內存的分配與回收兩個問題,之前已經和大家談過java回收的相關知識,今天來和大家聊聊java對象的在內存中的分配。通俗的講,對

jvm記憶體分配垃圾回收機制

問題: 1、垃圾回收目標物件? 2、什麼時間進行垃圾回收?(面試最常見的問題之一) 3、jvm怎樣進行垃圾回收? jvm記憶體分配 執行緒共享區域 1、 堆 2、方法區 執行緒私有區域 1、jvm棧 2、本地方法棧 3、程式計數器 由於虛擬機器棧,

jvm學習筆記(3)——java物件的記憶體分配物件的回收(GC)

引言:         之前的文章已經提過,java物件例項是存放在堆上的,至於是在伊甸區、存活區還是老年區,這些都是從物件回收(GC)角度來進行的邏輯劃分。所以我們先說物件的回收(GC),然後再依據GC的策略來說明新的物件具體在哪個區生成。 GC(Garbage C