c#:使用using关键字自动释放资源未必一定就会有明显好处

记录这篇文章的灵感来源来自今天下班前与同事的小小争论,我现在开发的一个项目中,有这样一段代码:

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 < max; i++)
            {
                SampleClass c = new SampleClass() { Name = i.ToString().PadLeft(1024, '0') };
                c.ToXMLWithUsing();
            }
            watch.Stop();
            Console.WriteLine("完成,{0}次操作共耗时:{1}毫秒,平均{2}毫秒/次!", max, watch.ElapsedMilliseconds, watch.ElapsedMilliseconds /(decimal)max);
            Console.ReadKey();
        }
    }
}

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 < max; i++)
            {
                SampleClass c = new SampleClass() { Name = i.ToString().PadLeft(1024, '0') };
                c.ToXMLNoUsing();
            }

            watch.Stop();
            Console.WriteLine("完成,{0}次操作共耗时:{1}毫秒,平均{2}毫秒/次!", max, watch.ElapsedMilliseconds, watch.ElapsedMilliseconds / (decimal)max);
            Console.ReadKey();
        }
    }
}

编译后,同时运行这二个程序,同时利用任务管理器观察内存使用情况:

反复多次运行比较,发现其实二者占用的内存几乎完全相同,这说明GC还是很给力的!

而且从执行时间上看,不用Using,反而更快,这也容易理解:用Using相当于每次都要调用Dispose()方法,这会带来一些系统开销;而不用Using,GC会在适当的时机批量回收资源,性能反而更好。(当然:这个结论不是要误导大家不用using,对于using还是推荐使用的!我的用意在于大家对于一些具体问题要具体分析,不可纯教条主义,一味迷信某些主流的观点)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏tkokof 的技术,小趣及杂念

Sweet Snippet 系列之 有序列表

很朴素的一种想法,为了维持 List 有序,我们可以在 Add 操作之后进行 Sort 操作(Remove 操作后不需要重新 Sort):

5410
来自专栏非著名程序员

Android开发工具类之HttpUtils

今天我们讲常用的开发工具类之HttpUtils,我发现上两次,我对于每个方法都进行了一定的解释,有人跟我评论和留言说,不用我解释,这么简单,这么明显的使用方法,...

31350
来自专栏c#开发者

Winform 的一个多线程绑定DataGrid数据源的例子

我们都知道简单的运用多线程的方法有 1/ Thread thread=new Thread(new StartThread(this.method))     ...

31590
来自专栏.NET后端开发

ADO.NET入门教程(七) 谈谈Command对象高级应用

摘要 在上一篇文章《你必须知道的ADO.NET(六) 谈谈Command对象与数据检索》中,我详细讲解了Command对象的基础知识以及基本用法。作为ADO.N...

53590
来自专栏飞扬的花生

C#中返回值封装

      在平时开发过程中常常需要取一个方法的返回值,BOSS写了一个返回值类,做个练习以备不时之需: 返回值支持泛型和非泛型 先贴上代码: 非泛型返回值类:...

277100
来自专栏GuZhenYin

[干货来袭]C#6.0新特性

微软昨天发布了新的VS 2015 ..随之而来的还有很多很多东西... .NET新版本 ASP.NET新版本...等等..太多..实在没消化.. 分享一下也是昨...

20480
来自专栏hbbliyong

C#基础知识回顾-- 反射(4)

从程序集获得类型   先说点题外话,现在技术真的发展太快了。我这边还很多东西半生不熟 呢,那边又出现了好多有趣的新东西让你眼红不已。学还是不学这还真是 个问题。...

29060
来自专栏跟着阿笨一起玩NET

DateTime.TryParseExact 万能时间格式转化

本文转载:http://blog.csdn.net/gaofang2009/article/details/6073231

25410
来自专栏跟着阿笨一起玩NET

浅谈WebService开发(一)

       简单通俗来说,就是企业之间、网站之间通过Internet来访问并使用在线服务,一些数据,由于安全性问题,不能提供数据库给其他单位使用,这时候可以使...

41430
来自专栏草根专栏

使用C# (.NET Core) 实现状态设计模式 (State Pattern)

51750

扫码关注云+社区

领取腾讯云代金券