1. 程式人生 > >.NET Memory Profiler 託管環境記憶體檢測工具,.net記憶體回收與Dispose﹐Close﹐Finalize方法

.NET Memory Profiler 託管環境記憶體檢測工具,.net記憶體回收與Dispose﹐Close﹐Finalize方法


2.使用物件
3.釋放物件

二.建立物件
1.建立物件實際分為兩個步驟?變數型別宣告和初始化物件

2.變數型別宣告(declare),如?

FileStream fs
這行程式碼會在當前的變數作用域空間(棧或堆)裡建立一個叫做fs的變數?至少四個位元組吧(因為要存一個物件的地址)

3.初始化物件
物件在使用(呼叫其方法或屬性)前?必須進行初始化。
如?


fs = new FileStream(@"C:\test.txt",FileMode.OpenOrCreate);
這行程式碼會分成3個步驟?
a.在託管堆中分配一塊記憶體?其大小等於FileStream中所有欄位(當然不包括靜態的)的記憶體總和加上MS認為需要的其它東東。
b.初始化物件的欄位(值型別的把其位全部初始化成0,物件初始化為null?當然string是一個例外?它被初始化成空字串)
c.呼叫FileStream相應的構造器?這裡會初始化一個非託管資源(檔案)的私有欄位。

三.使用物件
使用物件就沒什麼講的?就是呼叫物件的方法(或屬性等)來完成某個功能當然為了釋放物件而呼叫的方法其範疇應不屬於此類中(現在提到的Finalize等)

四.釋放物件
1.釋放物件也就是說這個物件我已經不需要了?現在我要把其釋放?以便把其在堆上所佔用的記憶體空間給收回來(當然變數名的記憶體空間就不需要管了?因為它會隨其作用域自動消失)

2. .net自動進行記憶體管理?也就是說當它判斷一個物件沒有用了(當然有自己的演算法)?它就會將其記憶體給自動收回來?但是其收回的時間一般不確定(當.net認為記憶體緊張時?它就會開始)

BTW:其實我們就是想自己收回物件的記憶體也不可能?因為MS沒有提供途徑(GC.Collect也是啟動.net的記憶體收集功能)

五.第一個結論
在net中使用物件很簡單?建立物件之後直接使用就可以了?不用了也不要去管它?垃圾收集器會幫你把記憶體要回來的。

六.例外
當物件的成員引用了一個非託管資源時(不在託管堆上分配的記憶體或資源?像檔案?資料庫連線等等)?下面以一個例子來說明?
System.IO.FileStream類別?這是.net基本類庫提供的一個非託管資源(檔案)封裝物件(用Reflector工具反編譯mscorlib.dll可見其程式碼)

1.FileStream毫無疑問封裝了一個非託管資源

觀其原始碼發現有這樣一個私有成員?


private SafeFileHandle _handle;
 通過構造器呼叫的Init方法可以發現這個成員的初始化程式碼?


this._handle = Win32Native.SafeCreateFile(text2, num1, share, secAttrs, mode, num2,  
Win32Native.NULL);
 而後者實際上就是kernel32.dll中的CreateFile方法?它返回一個HANDLE(即非託管資源引用)

2.我們先來使用這個類別?

 1using System;
 2using System.IO;
 3
 4public class TestFileStream
 5{
 6    public static void Main(string[] args)
 7    {    
 8           //建立一個FileStream物件
 Array        FileStream fs = new FileStream(@"C:\test.txt",FileMode.OpenOrCreate);        
10        Console.WriteLine("您可以嘗試在系統中刪除c盤下的test.txt(回車鍵繼續)");
11        //暫停程式執行?並嘗試在系統中刪除那個檔案
12        Console.ReadLine();
13
14        //刪除檔案測試
15        try
16        {
17            File.Delete(@"c:\test.txt");
18        }
1Array        catch (IOException ex)
20        {
21            Console.WriteLine("[Error]程式刪除檔案失敗?{0}",ex.Message);
22        }
23    }
24}


3.在程式掛起時(Console.ReadLine等待輸入)?刪除檔案會失敗?很容易理解?因為檔案開啟後沒有將其關閉?系統不知道這個檔案是否還有用?所以幫我們保護這個檔案(理所當然?那個非託管資源所使用的記憶體還被程式佔用著)

4.但是在程式執行完後?我們再嘗試刪除檔案?成功?為什麼?(fs不是沒有關閉那個SafeFileHandle嗎?)
當然您可以說?windows作業系統在一個程序結束後會自動回收其資源?沒錯(但是如果是com就慘了?因為com是存在於自己的獨立程序內?而作業系統不負責這個:(   )?不過這裡不是因為windows作業系統的功能?而是.net垃圾收集器幫的忙。

5.看下面這個例子

 1using System;
 2using System.IO;
 3
 4public class TestFileStream
 5{
 6    public static void Main(string[] args)
 7    {
 8        //建立一個FileStream物件
 Array        FileStream fs = new FileStream(@"C:\test.txt", FileMode.OpenOrCreate);
10        Console.WriteLine("您可以嘗試在系統中刪除c盤下的test.txt(回車鍵繼續)");
11        //暫停程式執行?並嘗試在系統中刪除那個檔案
12        Console.ReadLine();
13
14        /**//*進行垃圾收集*/
15        GC.Collect();
16        Console.WriteLine("再刪一下試試");
17        Console.ReadLine();
18    }
1Array}
 6.注意中間那行程式碼:

GC.Collect();
這是強制要.net垃圾收集器進行垃圾收集。
我們再去嘗試刪除test.txt?居然可以被刪除了?為什麼呀?(fs不是沒有關閉那個SafeFileHandle嗎?)?讓我細細道來?

7.我們首先了解一下.net垃圾收集器進行垃圾收集的四種時機(參見?.net框架程式設計 李建忠譯)
a.最常見的?當.net覺得合適時?例如它感到記憶體緊張了(?語稱為?0代物件充滿)
b.微軟強烈不建議使用的?GC的Collect方法呼叫(就是我們上面用的這種啦?因為會降低效能?會掛起程序, 等等?反正聽微軟的吧。當然某些時候可以用?就像我上面用來測試的程式碼?呵呵...)
c.應用程式域解除安裝時(AppDomain)
d.CLR被關閉時

8.現在我們可以明白第1個例子為什麼在程式結束後文件可以被刪除?因為CLR被關閉時?.net執行了垃圾收集(也就是等同於第二個例子的GC.Collect()程式碼)

Array.所以現在所有的問題都集中到垃圾收集上面?它做了什麼?

a.垃圾收集器在判斷一個物件不會再被引用到後?就開始對它進行垃圾收集(即回收記憶體)
b.清空記憶體(即把託管堆中的記憶體收回來)
c.但是物件的有些欄位引用到了非託管資源怎麼辦?如FileStream的_handle
d.所以我們必須告訴垃圾收集器?在你回收我的記憶體之前?先幫我執行一個方法來收回我的非託管資源?以免

託管堆的記憶體被你回收了?而我引用的非託管資源的記憶體卻被洩漏了。
e.這個方法就是Finalize()?也就是C#的 ~ClassName() 方法(同C++中的析構語法)
f.所以一個物件如果存在Finalize方法時?垃圾收集器在收回它的記憶體之前就會自動呼叫這個方法
g.這樣我們就可以把那些東東(非託管資源)給清理乾淨了

由此看來?垃圾收集器提供的這種機制就是為了更好的完善.net的自動記憶體管理的功能?讓我們也可以參與到垃圾收集中去

10.我們再來看看GC.Collect()這行程式碼或CLR關閉時.Net做了什麼?
a.垃圾收集器啟動?發現fs引用的那個物件已經沒用了(當然CLR關閉時才不管你有沒有用?通通回收)?於是對它進行記憶體回收
b.發現fs的型別?FileStream提供了Finalize方法?於是先呼叫這個方法
(以下通過Reflector繼續)
c.Finalize方法中有 this._handle.Dispose()程式碼?於是呼叫SafeHandler.Dispose()
d.接著轉到(當然好多個圈?您悠著點...)SafeFileHandle.ReleaseHandle方法?發現程式碼?Win32Native.CloseHandle() (即關閉非託管資源--檔案HANDLE)

真相大白?原來是垃圾收集器幫我們關閉了那個非託管資源(當然還是通過我們自己寫的Finalize方法)?因此後面就可以刪除檔案了。

11.有人會問?好像我們平時在使用FileStream物件時?沒這麼複雜呀?
答?Very Good!

一部分人?是因為大家都和我的例1一樣有好運氣?那個C盤下的test.txt檔案自從被建立後?我壓根就不會再去用它?管它這部分資源有沒有被洩漏?有沒有被鎖定?最後程式結束時?被垃圾收集器幫了忙?把忘了關閉的檔案HANDLE給收回來了。

剩下的一部分人?在程式裡埋下了一顆"啞彈"?不知什麼時候會爆炸?就像我例子中的File.Delete方法就出現了異常。

(不過我覺得)絕大多數人?是在看了很多諸如.net程式設計忠告?Microsoft強烈建議?MSDN標準做法等等等等( 還有我這篇blog?呵呵)之後?知道了在使用如FileStream,SqlConnection這些東東時?必須將其Close。

12.Close與Dispose
檢視我們那兩個例子的程式碼?都是不標準的?正確做法應該在使用完那個FileStream後?呼叫fs.Close()將其關閉?以保證資源的安全。

附?正確做法

 1using System;
 2using System.IO;
 3
 4public class TestFileStream
 5{
 6    public static void Main(string[] args)
 7    {
 8        //建立一個FileStream物件
 Array        FileStream fs = new FileStream(@"C:\test.txt", FileMode.OpenOrCreate);
10
11        /**//*在用完FileStream後關閉*/
12        fs.Close();
13
14        //刪除檔案測試
15        try
16        {
17            File.Delete(@"c:\test.txt");
18        }
1Array        catch (IOException ex)
20        {
21            Console.WriteLine("[Error]程式刪除檔案失敗?{0}", ex.Message);
22        }
23    }
24}
 

13.有人舉手?講這麼多?早告訴我呼叫fs.Close不就得了。
哥們?fs.Close()方法是由您寫的?調不呼叫?手在您身上?您不呼叫的話?哪天程式出了問題?您有會叫?微軟真垃圾?.net真不穩定?還是java好?安全?可靠...    為防您的國罵?MS只好在垃圾收集中加這一款?以防不測...

14.Dispose模式
認真檢視.net類庫中的那些基本類別?凡是有Finalize方法的類別?基本上都提供了諸如Dispose,Close,Dispose(bool)等方法(FileStream也不例外)

15.其實不管是Dispose,Close,Finalize方法?最終應該都是執行相同的程式碼
區別?
Finalize方法?只能由微軟呼叫
Dispose和Close方法?提供給您呼叫
因此在您使用完那些類別後?那就直接呼叫Close吧(沒有Close?再呼叫Dispose方法)?當然萬一您忘了?也別擔心?還有垃圾收集器幫您墊後。

七.第二個結論?
1.在您開發一個封裝非託管資源(即類中的欄位引用到了非託管資源)的類別時?
A:強烈建議您提供Finalize方法進行非託管資源的釋放?.net垃圾收集器不會幫您自動回收那部分資源?而是通過呼叫您的Finalize方法來幫您釋放。(這樣可以保證?在使用您類別的那位程式設計師忘了手動回收記憶體時?還可通過垃圾收集器來補救)

B.強烈建議您提供一個Close或Dispose方法?以便使用您類別的程式設計師可以手動釋放您的類別中的非託管資源。(參見.net框架程式設計 自動記憶體管理一章實現Dispose模式)

C.如果類別封裝了像FileStream這樣的物件(即對非託管資源的再次封裝)時?一般也應該提供一 個Close或Dispose方法?除非您的這個成員保證在每次使用後?都被正常的關閉?即對呼叫者透明。

2.在您使用一個封裝非託管資源的類別時?
A:強烈建議您在明確知道這個類別沒有用之後?呼叫其提供的Close或Dispose方法手動釋放其非託管資源的 記憶體。有道是?有借有還?再借不難;借了不還?再借休想~~

B:注意在手動釋放後?不要再呼叫該物件的相關方法了?因為物件已經損毀了

再次BTW:不管是Finalize?Close還是Dispose?您都無法顯式釋放託管堆記憶體?它們永遠是微軟的"私人財產 "?)
http://www.cnblogs.com/tsoukw/archive/2006/12/08/586525.html


以上內容由 華夏名網 蒐集整理,如轉載請註明原文出處,並保留這一部分內容。

“華夏名網” http://www.sudu.cn 和 http://www.bigwww.com 是成都飛數科技有限公司的網路服務品牌,專業經營虛擬主機,域名註冊,VPS,伺服器租用業務。公司創建於2002年,經過6年的高速發展,“華夏名網”已經成為我國一家知名的網際網路服務提供商,被國外權威機構webhosting.info評價為十大IDC服務商之一。

華夏名網網址導航: 虛擬主機 雙線主機 主機 域名註冊 cn域名 域名 伺服器租用 酷睿伺服器 vps vps主機

相關推薦

.NET Memory Profiler 託管環境記憶體檢測工具.net記憶體回收DisposeCloseFinalize方法

2.使用物件 3.釋放物件 二.建立物件 1.建立物件實際分為兩個步驟?變數型別宣告和初始化物件 2.變數型別宣告(declare),如? FileStream fs 這行程式碼會在當前的變數作用域空間(棧或堆)裡建立一個叫做fs的變數?至少四個位元組吧(因為要存一個物件的地址) 3.初始化物件

【C/C++】 記憶體檢測工具 memeory check

Backto C/C++ Index *nix – Valgrind: Valgrind是一款用於記憶體除錯、記憶體洩漏檢測以及效能分析的軟體開發工具。Valgrind這個名字取自北歐神話中英靈殿的入口。 Valgrind的最初作者是Julian Seward

記憶體檢測工具使用(Linux、VS)

一、Linux中記憶體檢測工具(valgrind) 記憶體檢查工具: valgrind linux上線上安裝:yum install valgrind 使用方法:     valgrind 你的

Windows和Linux記憶體檢測工具:ValgrindVisual Leak DetectorCppCheck Cpplint

1 Linux記憶體洩漏檢測工具ValgrindValgrind簡介        Valgrind是一套Linux下,開放原始碼(GPL V2)的模擬除錯工具的集合。Valgrind由核心(core)以及基於核心的其他除錯工具組成。核心類似於一個框架(framework),

iOS記憶體檢測工具Analyze的使用

XCode的Analyze可以分析到專案哪裡有記憶體洩露. 方法:xcode----product-----Analyze(快捷鍵:Shift + Cmd + B) iOS的分析工具可以發現編譯中的warning,記憶體洩漏隱患,甚至還可以檢查出log

非常好用的記憶體檢測工具

推薦理由:準確、快速大家比較熟悉的記憶體檢測工具有MemTest、微軟記憶體檢測(Microsoft Memory Diagnostic)等。但就本人的使用經歷來說,微軟的記憶體檢測工具更實用一些。下載地址:http://www.box.net/shared/03b7xbvk

Android 記憶體檢測工具

所謂記憶體洩漏,是指本該被回收的記憶體由於某種原因繞開了GC回收演算法,從而導致該記憶體無法被有效資料使用而使得總記憶體減小的情況。 記憶體洩漏會導致記憶體消耗的增加,大量的消耗會使得APP OOM,特別是在一些記憶體比較小的機器上。下面我們看看有哪些工具可以

Linux下記憶體檢測工具:asan

 Linux下記憶體檢測工具:asan ASAN(Address-Sanitizier)早先是LLVM中的特性,後被加入GCC 4.8,在GCC 4.9後加入對ARM平臺的支援。因此GCC

VLD(C++記憶體檢測工具學習2)

本文簡要描述一下在Qt應用中使用VLD來檢測記憶體洩露。本次測試環境:QtCreator2.3 + Qt4.7.4-vs2008 + VS2008 Express. 假定安裝到c:/dev/vld-2.2目錄下。 注:vld最初發表在codeproject.com,這個

Visual Leak Detector 2.2.3 Visual C++記憶體檢測工具

         Visual Leak Detector是一款免費的、健全的、開源的Visual C++記憶體洩露檢測系統。相比Visual C++自帶的記憶體檢測機制,Visual Leak De

AppScan安全檢測工具檢測出的問題解決

package com.common.util; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; impo

centos 7安裝部署java jdk 8,設定java環境變數(超詳細其他linux系統也可通過該方法安裝java,配置java環境變數)

前置配置 作業系統:CentOS Linux release 7.5.1804 Java版本號:jdk1.8.0_191 #OS版本號查詢 [[email protected] ~]$ cat

記憶體溢位時儲存記憶體快照:-XX:+HeapDumpOnOutOfMemoryError

-XX:+HeapDumpOnOutOfMemoryError該配置會把快照儲存在使用者目錄或者tomcat目錄下,也可以通過 -XX:HeapDumpPath=/tmp/heapdump.hprof 來顯示指定路徑此外,OnOutOfMemoryError引數允許使用者指定

在CentOS/RHEL 7中使用hostnamectl的命令列工具檢視或修改主機名相關的配置

在CentOS/RHEL 7中,有個叫hostnamectl的命令列工具,它允許你檢視或修改與主機名相關的配置。 要檢視主機名相關的設定: $ hostnamectl status 只檢視靜態、瞬態或靈活主機名,分別使用“--static”,“--transien

Tensorflow設定視訊記憶體自適應視訊記憶體比例

用慣了theano.再用tensoflow發現一執行視訊記憶體就滿載了,嚇得我吃了一個蘋果。 用天朝搜尋引擎毛都搜不到,於是翻牆找了下問題的解決方法,原來有兩種 1. 按比例 config = tf.ConfigProto() config.gpu_options.pe

JVM記憶體分配策略及垃圾回收演算法

本人免費整理了Java高階資料,一共30G,需要自己領取; 傳送門:https://mp.weixin.qq.com/s/J

Android Studio Profiler Memory記憶體分析工具)的簡單使用及問題

Memory Profiler 是 Android Studio自帶的記憶體分析工具,可以幫助開發者很好的檢測記憶體的使用,在出現問題時,也能比較方便的分析定位問題,不過在使用的時候,好像並非像自己一開始設想的樣子。 如何檢視整體的記憶體使用概況 如果想要看一個APP整體記憶體的使用,看APP heap就

Android記憶體分析工具Memory Profiler

一、前言 我們知道,Android系統檢測到app有不再使用物件時,就會進行記憶體回收相關的工作。 儘管Android檢測無用物件、回收記憶體的方法在不斷改進, 但在目前所有的Android版本中,進行上述工作時,系統仍需要短暫地停止app的執行。 在大

關於.net託管環境下struct型別的記憶體佈局的認識

熟悉C/C++的朋友都知道,struct型別中的成員在記憶體中都是按順序依次存放的,即按成員的宣告順序,並且通常是按成員中佔用空間最大的成員進行對齊的。 然而,到了.net託管環境中,則有所不同。CLR為我們提供了兩種不同的結構成員記憶體佈局方式:LayoutKind.Se

Android內存優化1 內存檢測工具1 Memory Monitor檢測內存泄露

pri 二次 多個 內存泄漏 可選 分配內存 blog android .net 上篇說了一些性能優化的理論部分,主要是回顧一下,有了理論,小平同誌又講了,實踐是檢驗真理的唯一標準,對於內存泄露的問題,現在通過Android Studio自帶工具Memory Monitor