当前位置:编程学习 > C#/ASP.NET >>

请教高手,C#如何找到泄漏的资源、什么是内存快照?顶着有分,谢谢

请教高手,C#如何找到泄漏的资源、什么是内存快照?顶着有分,谢谢 --------------------编程问答-------------------- 对于“泄露的资源”请你先举出具体的例子。因为这个词儿在.net中历来会有很大的歧义,我不能乱说。 --------------------编程问答-------------------- 这两个词儿,在c程序员那里可以乱说,因为c程序极其低级和单纯。

而托管系统下的程序比较灵活,框架丰富,程序模块和数据是动态的,地址是浮动的(映射的),因此这些词儿不适合照搬。 --------------------编程问答-------------------- --------------------编程问答-------------------- 嗯,你也可能被忽悠的不轻。 --------------------编程问答-------------------- --------------------编程问答-------------------- 难道木有高手知道吗?

比如,下面的非托管资源泄漏,我如何才能找出来

private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.Green);
        }




--------------------编程问答-------------------- 除 --------------------编程问答-------------------- 不懂你说的"泄露的资源" --------------------编程问答--------------------
引用 8 楼 junlinfushi 的回复:
不懂你说的"泄露的资源"


Pen pen = new Pen(Color.Green);
没调用pen.Dispose(); 不就是资源泄漏吗? --------------------编程问答-------------------- 我百度的:
MFC中的CMemoryState 类。
  这个类非常有用,它可以给当前内存照个快照,并可以将内存快照进行比对。如果你想确认程序在某个时段中分配的内存全部被正确的释放,那可以在这个时段开始时照个快照,结束后再照一个。如果这个两个快照不一样,说明这个时段中有内存泄漏了。
  这个类很容易使用。MSDN上的说明很清楚,还有一个例子。
  EMule在Emule.cpp文件中申明了这个类的三个静态变量
static CMemoryState oldMemState, newMemState, diffMemState;
  在BOOL CemuleApp::InitInstance()方法中就用到了它们。方法开始处先照了个快照。
oldMemState.Checkpoint();
  在该方法快结束时双照了一个并进行了比较,如果不一样,就说明有内存泄漏了。把泄漏的内存情况导出到output窗口。
newMemState.Checkpoint();
if (diffMemState.Difference(oldMemState, newMemState))
{
   TRACE("Memory usage:\n");
   diffMemState.DumpStatistics();
}
  一般可以用_DEBUG宏控制让这些代码只在调试阶段被编译。
  虽然这个类是MFC中的,其实是包装了Run-Time中几个Debug方法,但用起来很方便。如果不想用MFC,也可以直接把这个类抠出来用就是了。我就是这么干的,因为我都是用WTL。
  值得注意的是,快照的时机要掐准。最好是在刚开始就在关键部位掐好,每加入一点新功能就跑一跑。这种方式可以在程序一出现内存泄漏时就让你知道。在晚期再加这个机制就没什么用了,因为它并不能分析和定位内存泄漏。
  有一种情况要注意一下。如果掐的时机不准,很容易误报。比如我在main函数的开始和结尾掐快照,直觉上觉得应该是没问题了。但是如果程序中有一个全局对象,那么它会在main()之前被构造。假如这个对象有一个成员变量是一个STL::string,构造时为空,但在程序运行中给它赋了值。这时 string内部会new内存块出来。同样这个对象会在main()之后被析构,这时string内部new出来的内存才会被delete,但这已经超来了第二个快照的范围。这时两个快照是不一致的,但其实没有内存泄漏。 --------------------编程问答--------------------
引用 10 楼 wind_cloud2011 的回复:
MFC中的CMemoryState 类。



感谢哥们,我用C#,请问有没有C#检测资源泄漏 --------------------编程问答--------------------
引用 9 楼 corn8888 的回复:
Quote: 引用 8 楼 junlinfushi 的回复:

不懂你说的"泄露的资源"


Pen pen = new Pen(Color.Green);
没调用pen.Dispose(); 不就是资源泄漏吗?
你看一下这个http://blog.csdn.net/wnln25/article/details/7194914 --------------------编程问答--------------------
引用 8 楼 junlinfushi 的回复:
不懂你说的"泄露的资源"

当一个对象被NEW以后,就存在于内存当中了,使用完了要对这个对象进行释放,意思就是在内存把它清除掉。
但是在.Net中,有很多对象都是托管的,意思就是:某对象没有被手动释放(没有调用其Diapose方法),当此对象不再使用时,系统会自动将其释放。
非托管就是,如果不手动释放,就不会被释放了。
资源泄露就是指没有被托管的对象不使用后没有被释放掉的情况。
不知道解释的准不准确。 --------------------编程问答-------------------- http://msdn.microsoft.com/en-us/library/ee658248.aspx,英文的 --------------------编程问答-------------------- .NET内存管理剖析及资源回收编程解决方案
http://hi.baidu.com/donghaozheng/item/49ea11ef0168e1c3baf37d68 --------------------编程问答-------------------- 请问各位有没有好的工具 --------------------编程问答-------------------- 好吧,之前误会你的意思了。

你说的“内存泄露”,是指那些托管的内存,没有按照预期被GC回收,也就是存在生命周期被延长的情况,是不是。

因为我们通常不把这归作内存泄漏的范畴,只有非托管内存,才有泄漏的可能。

参考:

http://blogs.msdn.com/b/tess/archive/2008/02/20/net-debugging-demos-lab-3-memory-review.aspx
http://stackoverflow.com/questions/5185663/can-clr-profiler-be-used-to-find-memory-leaks
http://blogs.microsoft.co.il/sasha/2012/05/04/pinpointing-memory-leaks-with-clr-profiler-heap-graphs/ --------------------编程问答--------------------
引用 6 楼 corn8888 的回复:
难道木有高手知道吗?

比如,下面的非托管资源泄漏,我如何才能找出来

private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.Green);
        }


没泄露呀,还有析构函数等着他呢,没调用pen.Dispose();只是内存释放的晚一些而已,你看看IDisposable接口的标准实现方式就知道了
--------------------编程问答--------------------
引用 18 楼 bigbaldy 的回复:
Quote: 引用 6 楼 corn8888 的回复:

难道木有高手知道吗?

比如,下面的非托管资源泄漏,我如何才能找出来

private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.Green);
        }


没泄露呀,还有析构函数等着他呢,没调用pen.Dispose();只是内存释放的晚一些而已,你看看IDisposable接口的标准实现方式就知道了


确定吗,pen不是需要显式调用Dispose()吗? --------------------编程问答-------------------- 说个不太严谨的,现在真不敢乱说了。貌似托管代码没有必须调用Dispose的,因为有垃圾回收机制,你这句在一个函数里面,是个局部对象,函数执行完第一轮垃圾回收就把它收了 --------------------编程问答--------------------
引用 19 楼 corn8888 的回复:
Quote: 引用 18 楼 bigbaldy 的回复:

Quote: 引用 6 楼 corn8888 的回复:

难道木有高手知道吗?

比如,下面的非托管资源泄漏,我如何才能找出来

private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Pen pen = new Pen(Color.Green);
        }


没泄露呀,还有析构函数等着他呢,没调用pen.Dispose();只是内存释放的晚一些而已,你看看IDisposable接口的标准实现方式就知道了


确定吗,pen不是需要显式调用Dispose()吗?


确定,显式调用Dispose()只是为了及时释放内存,你不释放GC将来也会帮你释放,要不怎么说.net程序员终于脱离了内存释放的麻烦

--------------------编程问答-------------------- 可以用一段时间,就出现“内存不足”的提示,不知为什么?

我用MemProfiler查看,有很多Font、Pen、Brush没释放? --------------------编程问答-------------------- 泄露的资源可否理解成 还没被.NET垃圾机制回收,而在程序代码中又用不到的一些空间 --------------------编程问答--------------------
引用 23 楼 sammy_luo 的回复:
泄露的资源可否理解成 还没被.NET垃圾机制回收,而在程序代码中又用不到的一些空间


有这种情况 --------------------编程问答-------------------- Font、Pen、Brush 这些是不会侧漏的,GC会回收,你还是查查有没循环事例化并且被引用的。 --------------------编程问答-------------------- 参考这个:http://blog.csdn.net/fhzh520/article/details/7872305 --------------------编程问答-------------------- 帖子中间的讨论我没有看,不知道我这里的回复会不会跟上面重复。如果重复请见谅。


最常被说成是.net的“泄露”的罪魁祸首,是事件的释放问题。例如我们写
a.Click += a_clicked;
这个 a_clicked 方法声明在当前的对象(暂且叫做对象b,类型为B),而对象a是一个全局的窗体或者甚至是一个静态的对象,那么实际上对象b即使再也不用了,GC往往也无法回收它。这个时候,在a的Dispose()方法中,我们必须写
a.Click -= a_Clicked;
并且显示调用b.Dispose()才能保证不会出现内存泄露问题。

简单来说,因为a对象生命期比b长太多了,而b先注销,因此如果我们不手动注销这种事件,就会在大量新的B对象不断被动态创建时看到貌似出现内存泄露的现象。

当然可以采取修改a的Click事件的定义,让它实现为“弱引用事件”的方式。但是这样编程非常麻烦,而且性能实在是太差了。对于大量使用事件编程驱动的程序,每一分钟都可能销毁上万个对象的系统,事件的弱引用可能不是一个好的选择。而这种 -= 的手动注销事件的写法则是个好的选择。实际上你不需要对所有的“短生命期”的对象都这样去保证注销事件,你只需要在测试出“内存泄露”时才去采取措施。仅需要比较粗放地处理就行了,不需要画蛇添足地进行过度调控。

那么如何检测出某个对象可能泄露了?我们可以简单地做一个通知机制,例如我们在不断地调用成千上万的测试程序时,我们知道某些测试用例里的测试对象应该顶多仅生存1、2秒钟,显然如果其10秒钟还没有被GC回收就不正常了,于是我们可以监控它是否真的已经被回收了。例如
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;

namespace Common
{
    public static class OverflowMonitor
    {
        private static Timer tmr;

        private static void xx(object state)
        {
            lock (sessions)
                (from x in sessions
                 where x.theTime < DateTime.Now
                 select x)
                     .ToList()
                     .ForEach(x =>
                     {
                         Debug.Assert(!x.reff.IsAlive);
                         sessions.Remove(x);
                     });
        }

        [Conditional("DEBUG")]
        public static void Register(object target, DateTime theTime)
        {
            if (tmr == null)
                tmr = new Timer(xx, null, 10000, 10000);
            var sn = new Session
            {
                reff = new WeakReference(target),
                theTime = theTime,
            };
            lock (sessions)
                sessions.Add(sn);
        }

        private static List<Session> sessions = new List<Session>();

        private class Session
        {
            public WeakReference reff;
            public DateTime theTime;
        }
    }
}

这把我们要监控的对象,放入一个“弱引用”中,然后定时监控其生命期是否过长。这仅仅在测试中使用,例如
OverflowMonitor.Register(obj, DateTime.Now.AddSeconds(10));
就是如果对象obj超过10秒钟还不释放掉我们就收到一个异常。在自动化测试时,我们希望异常尽可能地早爆发出来,这样才能最好地保证产品的稳定性。而检测内存泄露,需要现有想象力,然后把这个想象力变成测试用例和测试数据,进行执行。而在发布的产品中,我们通过Conditional这个标签通知编译器去掉了这种测试,也不会影响发布产品的执行性能。 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 比如

for(int a=0; a<100000000; a++)
{
Pen pen = new Pen(Color.Green);
}


虽然最后会释放资源,但是,软件会越用越慢,出现提示“内存不足”的现象 --------------------编程问答-------------------- ID:sp1234,是高手。呵呵。支持 --------------------编程问答-------------------- 高手啊 高手,你 在哪儿? --------------------编程问答--------------------
引用 29 楼 corn8888 的回复:
比如

for(int a=0; a<100000000; a++)
{
Pen pen = new Pen(Color.Green);
}


虽然最后会释放资源,但是,软件会越用越慢,出现提示“内存不足”的现象


for(int a=0; a<100000000; a++)
{
    using(Pen pen = new Pen(Color.Green))
    {
        //todo
    }
}

养成这样写代码的习惯不就行了 --------------------编程问答--------------------
引用 32 楼 bigbaldy 的回复:
Quote: 引用 29 楼 corn8888 的回复:

比如

for(int a=0; a<100000000; a++)
{
Pen pen = new Pen(Color.Green);
}


虽然最后会释放资源,但是,软件会越用越慢,出现提示“内存不足”的现象


for(int a=0; a<100000000; a++)
{
    using(Pen pen = new Pen(Color.Green))
    {
        //todo
    }
}

养成这样写代码的习惯不就行了



但是有可能忘了,错误在所难免,而且用using,有时候不方便。

我现在就想找一款好的工具、有教程,用工具找出泄漏的资源


--------------------编程问答--------------------
引用 33 楼 corn8888 的回复:
但是有可能忘了,错误在所难免,而且用using,有时候不方便。

我现在就想找一款好的工具、有教程,用工具找出泄漏的资源


1.微软有Fxcop,免费的,好像可以检测
2.商业级的有Fortify,确定可以检测,我用过,哪有泄漏找得很清楚,而且修复建议里怎么改都给出了代码示例,并且可以自定义规则,不过好像没有破解版,单位花钱买的 --------------------编程问答-------------------- 除非你的程序太简单(例如只是用来配合人家宣传的一个小程序),否则误报一大堆。 --------------------编程问答-------------------- 既然有实际问题,干嘛一直在说一些理论的东西?
拿出你的代码,拿出你的问题,这样大家的讨论会更贴切点,你也能得到你所需要的 --------------------编程问答-------------------- 额, 为啥最近总拿这一个主线程的几乎无限循环代码在矫情是内存泄露???

兄弟,如果你是在主线程里搞这类无限循环,不管你是代码基本都会一个效果,卡死UI,内存爆掉 --------------------编程问答-------------------- 帮顶一下吧! --------------------编程问答-------------------- 主线程里,while(true)不写退出会是啥效果?效果和你描述的一样,UI卡死,内存崩溃?

那么这是不是要说while(true)也内存泄露了??

ok,你说你的循环不是个死循环,是有退出条件滴。但是我们的说,如果1w次循环可以让内存崩溃,那么你写1w次和写10001次,和while(true)完全木区别 --------------------编程问答-------------------- 我一般用.NET Memory Profiler。
stackoverflow上的相关贴子你可以参照一下
http://stackoverflow.com/questions/134086/what-strategies-and-tools-are-useful-for-finding-memory-leaks-in-net --------------------编程问答--------------------
引用 37 楼 wanghui0380 的回复:
额, 为啥最近总拿这一个主线程的几乎无限循环代码在矫情是内存泄露???

兄弟,如果你是在主线程里搞这类无限循环,不管你是代码基本都会一个效果,卡死UI,内存爆掉


我只是举个例子,可能不是在一个循环中,new了10000000,但也可能时间了,总共new了1000000,就会占着内存不放,直至程序退出。

中间就可能出现提示“内存不足” --------------------编程问答--------------------
引用 40 楼 sjyforg 的回复:
我一般用.NET Memory Profiler。
stackoverflow上的相关贴子你可以参照一下
http://stackoverflow.com/questions/134086/what-strategies-and-tools-are-useful-for-finding-memory-leaks-in-net


哥们,.NET Memory Profiler好用吗,我怎么感觉不大好用,还是我不会用? --------------------编程问答-------------------- 不明白你说的不好用是什么意思,我用起来觉得还是挺简单的。
网上有相关介绍的文章:

http://www.cnblogs.com/eaglet/archive/2008/09/05/1285169.html

http://lzy.iteye.com/blog/344317 --------------------编程问答--------------------
引用 43 楼 sjyforg 的回复:
不明白你说的不好用是什么意思,我用起来觉得还是挺简单的。
网上有相关介绍的文章:

http://www.cnblogs.com/eaglet/archive/2008/09/05/1285169.html

http://lzy.iteye.com/blog/344317



谢哥们,Mem Profiler提示的泄漏资源,我怎么感觉不准确,还是我分析的不对? --------------------编程问答-------------------- 我见过最多的是DataReader open之后没close,函数就return了。于是没多久就报数据库连接池被占满。

pen之类的托管对象,除非你真的吃饱了没事写了一个很长很长的循环,GC是可以自动回收的。

楼上很多检测的工具都不错,可惜我从没用过。今天又学习了一点新东西。 --------------------编程问答--------------------
引用 45 楼 yuwenge 的回复:
pen之类的托管对象,除非你真的吃饱了没事写了一个很长很长的循环,GC是可以自动回收的。


只是举例..........


补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,