c#使用using關鍵字自動釋放資源不一定有好處

ldzsl發表於2021-09-09

 

記錄這篇文章的靈感來源來自今天下班前與同事的小小爭論,我現在開發的一個專案中,有這樣一段程式碼:

public string ToXML()
        {
            string strXml = string.Empty;
            try
            {
                MemoryStream ms = new MemoryStream();
                XmlSerializer xml = new XmlSerializer(this.GetType());
                xml.Serialize(ms, this);
                byte[] arr = ms.ToArray();
                strXml = Encoding.UTF8.GetString(arr, 0, arr.Length);
                return strXml;
            }
            catch
            {
                return "";
            }
        }

同事說象MemoryStream這類資源,應該用using包起來自動釋放資源,否則會有記憶體洩漏問題。在using的使用上,我也同意應該使用using,但由於這類風格的程式碼在原專案中非常多(有一部分歷史原因),如果一一修改,工作量太大,時間不允許。於是我就在內心評估:如果不改,現在這種程式碼的風險到底有多大?

我想很多人都知道using(Resource res = new Resrouce){},其實相當於

Resource res = new Resrouce

try{}

catch{}

finally{res.Dispose();}

對比與現有程式碼的區別,無非就是資源沒有呼叫Dispose()釋放,但是CLR有強大的GC(垃圾回收)機制,方法呼叫完成後,方法體中建立的託管資源如果不再被使用,也一併會被GC列為可回收物件,所以就算開發人員沒有手動呼叫Dispose,其實CLR也會幫我們做這件事情,只是時機可能會晚一些而已。

於是有了下面的測試:

1.先建立一個示例用的Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml.Serialization;
 
namespace Model
{
    public class SampleClass
    {
        public string Name { set; get; }
 
 
        public string ToXMLNoUsing()
        {
            string strXml = string.Empty;
            try
            {
                MemoryStream ms = new MemoryStream();
                XmlSerializer xml = new XmlSerializer(this.GetType());
                xml.Serialize(ms, this);
                byte[] arr = ms.ToArray();
                strXml = Encoding.UTF8.GetString(arr, 0, arr.Length);
                return strXml;
            }
            catch
            {
                return "";
            }
        }
 
        public string ToXMLWithUsing()
        {
            string strXml = string.Empty;
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    XmlSerializer xml = new XmlSerializer(this.GetType());
                    xml.Serialize(ms, this);
                    byte[] arr = ms.ToArray();
                    strXml = Encoding.UTF8.GetString(arr, 0, arr.Length);
 
                }
                return strXml;
 
            }
            catch
            {
                return "";
            }
        }
 
    }
}

  

這其中的ToXML為了測試方便,故意分成了二個版本(一個不用using,一個用using)

2.再建立一個Console程式(命名為WithUsing),寫一段測試程式碼:

using System;
using System.Diagnostics;
using Model;
 
namespace WithUsing
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("開始折騰-WithUsing...");
            Stopwatch watch = new Stopwatch();
            int max = 100000;
 
            watch.Reset();
            watch.Start();
 
            for (int i = 0; i 

  

3.再建立一個Console程式(命名為NoUsing),寫一段測試程式碼:

using System;
using System.Diagnostics;
using Model;
 
namespace NoUsing
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("開始折騰-NoUsing...");
            Stopwatch watch = new Stopwatch();
            int max = 100000;
 
            watch.Reset();
            watch.Start();
            for (int i = 0; i 

  

編譯後,同時執行這二個程式,同時利用工作管理員觀察記憶體使用情況:

圖片描述

反覆多次執行比較,發現其實二者佔用的記憶體幾乎完全相同,這說明GC還是很給力的!

而且從執行時間上看,不用Using,反而更快,這也容易理解:用Using相當於每次都要呼叫Dispose()方法,這會帶來一些系統開銷;而不用Using,GC會在適當的時機批次回收資源,效能反而更好。(當然:這個結論不是要誤導大家不用using,對於using還是推薦使用的!我的用意在於大家對於一些具體問題要具體分析,不可純教條主義,一味迷信某些主流的觀點)。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2325/viewspace-2800403/,如需轉載,請註明出處,否則將追究法律責任。

相關文章