.NET程序内存泄漏排查的两种方式

概述

     .NET中托管内存在使用完毕后会在合适的时机被垃圾回收,非托管的内存则不会被自动回收,如果这些非托管的资源没有释放或者及时释放,程序长时间运行会导致内存慢慢被占满直到程序崩溃.

.NET中常见的内存泄漏主要有以下三种:

  • 静态变量泄露:

    静态变量中的成员所占用的内存如果不手动处理是无法自动释放的,如单例模式;

  • 非托管资源泄露:非托管资源不会自动回收,使用完成后需要手动释放,一般是通过实现dispose仿作实现释放,dispose一般写法如下:

    public class SampleClass : IDisposable
    {
        //演示创建一个非托管资源
        private IntPtr nativeResource = Marshal.AllocHGlobal(100);
     
        //演示创建一个托管资源
        private Test test = new Test();
        private bool disposed = false;
     
        /// <summary>
        /// 实现IDisposable中的Dispose方法
        /// </summary>
        public void Dispose()
        {
            //必须为true
            Dispose(true);
     
            //通知垃圾回收机制不再调用终结器(析构器)
            GC.SuppressFinalize(this);
        }
     
        /// <summary>
        /// 不是必要的,提供一个Close方法仅仅是为了更符合其他语言(如C++)的规范
        /// </summary>
        public void Close()
        {
            Dispose();
        }
     
        /// <summary>
        /// 必须,以备程序员忘记了显式调用Dispose方法
        /// </summary>
        ~SampleClass()
        {
            //必须为false
            Dispose(false);
        }
     
        /// <summary>
        /// 非密封类修饰用protected virtual
        /// 密封类修饰用private
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposed)
            {
                return;
            }
            if (disposing)
            {
                // 清理托管资源
                if (test != null)
                {
                    test.Dispose();
                    test = null;
                }
            }
            // 清理非托管资源
            if (nativeResource != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(nativeResource);
                nativeResource = IntPtr.Zero;
            }
            //让类型知道自己已经被释放
            disposed = true;
        }
     
        public void SamplePublicMethod()
        {
            if (disposed)
            {
                throw new ObjectDisposedException("SampleClass", "SampleClass is disposed");
            }
        }
    }
  • 事件委托导致资源泄露:这种一般使用完成记得解订阅就可以.

内存泄露排查方法

    方式1:通过vs附加进程debug方式

第一步:调试-》窗口-》显示诊断工具:

68fa4274954f673854d704290446bede.png

第二步:选择内存使用率-》截取快照,前后截图两次快照

6f727f0c51965574a08f8e69c3cbff48.png

28618e7e500581559ca94d54b847bdd3.png

第三步:分析增长的内存,双击垫块堆大小后增长的红色箭头:这里可以看到内存增长的数据类型:

8deb0d90d5391ee74abd95876c0baefa.png

d5e52329626a917d5a7ed69c29bd64b5.png

方式2:通过第三方的工具:.NET Memory Profiler,下载后按照默认安装方式安装,安装好后打开有6天的试用期,可以修改下注册表延长时限:

2060eb07d165ed84bc870bae599d12b4.jpeg

84dcf2c69a97c7ced0ff7a57f60a0d74.jpeg

注册好以后可以先附加进程,然后也是捕获两次内存快照,

9758eb3584bc9dec8787715ee8c4e417.png

9103ece0c604f0cc382abfd0528ad92a.png

然后通过快速增长的那部分村内去分析具体没有释放的类!

技术群:添加小编微信dotnet999

公众号:dotnet讲堂

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值