前言

一般来说.NET程序员是不用担心内存分配释放问题的,因为有垃圾收集器(GC)会自动帮你处理。但是GC只能收集那些不再使用的内存(根据对象是否被其它活动的对象所引用)来确定。所以如果代码编写不当的话,仍然会出现内存泄漏的问题,常见的情况有:一个静态变量引用了一个应该被释放的对象,事件注册后不解除注册,非托管资源使用后没有手动释放。不断的内存泄漏终会引起内存不足,挂掉你的程序。

对于这种内存泄漏问题,有很多的分析工具可以使用,常见的有CLRProfiler、ANTS Performance Profiler等。不过从vs2013起,vs自带了一个分析工具-Diagnostic Tool,默认debug时会自动打开,如果没有打开的话就按快捷键Ctrl+Alt+F2。

如下图: 

开始使用

这里以静态变量持有应释放的对象为例,简单介绍下使用方法。 
这里有个winform程序,主要功能即使点击按钮后,输出名为“jim”的个人信息:

private void button1_Click(object sender, EventArgs e)
{
var p = PersonManager.Get("jim");
label1.Text += p.Name + " " + p.Age + "\n";
}
  • 1
  • 2
  • 3
  • 4
  • 5

Person和PersonManager类的信息如下:

namespace MemLeak
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public byte[] BinaryData { get; set; }
}
public static class PersonManager
{
static List<Person> people = new List<Person>();
public static List<Person> People
{
get
{
return people;
}
}
public static Person Get(string name)
{
//正常逻辑
//var per = People.FirstOrDefault(o => o.Name == name);
//if(per==null)
//{
// per = new Person();
// per.Age = 23;
// per.Name = name;
// per.BinaryData = File.ReadAllBytes(@"D:\2.zip");//一个38MB的文件
// people.Add(per);
//}
//return per;
//错误逻辑
Person p = new Person();
p.Age = 23;
p.Name = name;
p.BinaryData = File.ReadAllBytes(@"D:\2.zip");//一个38MB的文件
people.Add(p);
return p;
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

1. 捕获内存快照

程序运行起来后,从下图可以看到内存占用大约在18M左右,此时点击“截取快照”新建一个快照: 

然后click按钮5次,然后再点击 截图快照 ,如下: 
 
从曲线图中可以明显看到内存从18M逐步增长到227M。第二次快照与第一次相比对象增加了19个,堆上的内存使用增加了191M左右。 
 
点击图中的(+19)字样,可以进入到快照详细对比界面。

2. 详细对比


如图所示,我们先来看下选中的那一行是什么意思: 

可以看到MemLeak.Person这个对象的计数差异为+5,计数是5。表示这两次快照之间这个Person对象从0个变成了5个增加了5个。大小差异是增加了195601040个字节,这几个从字面意思看都很好理解。唯一有点难度的可能是非独占大小(字节),一眼看不出来是干什么的。但是我们注意到了List<MemLeak.Person>对象的大小是68字节而非独占大小却是195601108字节。 
非独占大小的统计方式如下: 

其中最下层的stringbyte[],由于没有子节点了,所以它们的非独占大小就是它们本身的大小。Address的非独占大小=自己本身的大小+String的非独占大小(50字节)+Byte[]的非独占大小(100字节)=200字节。Customer的非独占大小=自己本身(100字节)+String的非独占大小(100字节)+Address的非独占大小(200字节)=400字节。 
所以这也就解释了List<MemLeak.Person>,自身大小仅是68字节,但是由于它是一个List内部包含了5个Person对象,所以它的非独占大小就是5个Person对象大小的和。

3. 哪里产生了泄漏?

这里我先将过滤器里“仅我的代码”和“折叠小型对象类型”前面的勾去掉,便于分析。 
 
因为我们值需要看当前程序集(MemLeak)的内存信息,所以在搜索类型名的框里直接输入我们程序集的名称,将其他一些没用的过滤掉。 

是不是清爽了很多! 
分析内存当然要拿占用内存增多最大的对象开刀,点击MemLeak.Person,在下面的“根的路径”视图中可以看到增加的5个Person对象是在一个Person[]数组中。 

但是我们好像并没有声明过这样的数组,所以继续展开: 
 
原来是在一个List里面,而且这个List还是静态的。这时候就要想到内存泄漏的原因,可能就是代码哪里的静态变量持续占有应该释放的对象了。然后更改为正确代码就OK了。

4. 查看对象中哪种数据类型占用内存较多?

切换到的引用选项卡(“引用的类型”)。 

可以看到本例中PersonByte[]类型的占用内存较多,所以我们就可以重点排查Person中哪里用到了Byte[]类型,进而去优化。

当初取消勾选的那两个选项是什么?

第一个是“仅我的代码”: 
勾上之后,会过滤掉那些.Net Runtime产生的一些对象和一些很常见的系统认为与你的程序无关的一些对象。

第二个是:“折叠小的对象类型”: 
勾上后,会过隐藏掉那些非独占大小小于托管堆总大小0.5%的对象。将这些小对象的非独占大小合并的父节点中。如下: 

这两个选项默认都勾上即可。

其它

对于生产环境中的软件,分析内存时可以多次抓取dump文件,用vs打开后分析比对。 
 
不过只有vs的企业版才有这个功能。


参考

Memory Usage Tool while debugging in Visual Studio 2015

【VS】使用vs2017自带的诊断工具(Diagnostic Tools)诊断程序的内存问题的更多相关文章

  1. VS 使用vs2017自带的诊断工具(Diagnostic Tools)诊断程序的内存问题

    前言 一般来说.NET程序员是不用担心内存分配释放问题的,因为有垃圾收集器(GC)会自动帮你处理.但是GC只能收集那些不再使用的内存(根据对象是否被其它活动的对象所引用)来确定.所以如果代码编写不当的 ...

  2. 如何禁用/关闭vs2017自带的Git工具的?

    对于用习惯了独立Git工具和命令行的人来说,看到Visual Studio自带的Git工具后,很是别扭,到处充满了不习惯,而且是不是还会出现电脑卡顿的现象(可能是我自身电脑配置一般的问题). 如何关闭 ...

  3. 容器内的Linux诊断工具0x.tools

    原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 Linux上有大量的问题诊断工具,如perf.bcc等,但这些诊断工具,虽然功能强大,但却需要很高的权限才可以使用 ...

  4. Vs2015 c# 诊断工具查看程序的占用情况

    windbg用着还不熟悉,dottrace  还要版权,着急查看程序的cpu 的使用情况,因为程序开启之后占用处理器资源较大,问题在哪里呢,于是点开了vs2015自带的诊断工具,以前偶尔打开过,没发现 ...

  5. 使用vs自带的性能诊断工具

    visual studio是个强大的集成开发环境,内置了程序性能诊断工具.下面通过两段代码进行介绍. static void Main( string[] args) { Test1(); Test2 ...

  6. vs2017诊断工具

    vs2017诊断工具

  7. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  8. [转]linux 系统监控、诊断工具之 IO wait

    1.问题: 最近在做日志的实时同步,上线之前是做过单份线上日志压力测试的,消息队列和客户端.本机都没问题,但是没想到上了第二份日志之后,问题来了: 集群中的某台机器 top 看到负载巨高,集群中的机器 ...

  9. Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap

    Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprob ...

随机推荐

  1. 我的一起开源网 www.17ky.net上线了

    .net开源生态的落后,使得.net开发人员所拥有的开源资源比其他语言的开发者少了很多,这也使得笔者很早之前就喜欢收集各种开源项目,经常会去逛codeplex,开源中国社区等网站,同时也喜欢在自己或公 ...

  2. 软工作业NO.2小学生线上杨永信——四则运算题目生成

    项目题目:实现一个自动生成小学四则运算题目的命令行程序 github地址:https://github.com/a249970271/Formula 驾驶员:梁沛诗 副驾驶:曾祎祺 项目说明 自然数: ...

  3. MyEclipse持续性开发教程:用JPA和Spring管理数据(二)

    MyEclipse红运年货节 在线购买低至69折!火爆开抢>> [MyEclipse最新版下载] 本教程介绍了MyEclipse中的一些基于JPA / Spring的功能.有关设置JPA项 ...

  4. NBUT 1223 Friends number 2010辽宁省赛

    Time limit  1000 ms Memory limit   131072 kB Paula and Tai are couple. There are many stories betwee ...

  5. 各大公司java后端开发面试题

    各大公司Java后端开发面试题总结 ThreadLocal(线程变量副本)Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量.采用空间换时间,它用于线程间的数据隔离 ...

  6. C/S架构和B/S架构

    本文内容整理自http://blog.csdn.net/tennysonsky/article/details/45062079 C/S架构和B/S架构是两种颇具影响力的软件体系结构.C/S是一种历史 ...

  7. 转:三种状态对象的使用及区别(Application,Session,Cookie)

    Application状态对象 Application 对象是HttpApplication 类的实例,将在客户端第一期从某个特定的ASP.NET应用程序虚拟目录中请求任何URL 资源时创建.对于We ...

  8. PyCharm:ModuleNotFoundError: No module named 'HTMLTestRunner'

    PyCharm找不到HTMLTestRunner,还是之前的原因PyCharm和之前命令行安装使用的不是一套资源,需要重新导入 查看旧HTMLTestRunner的路径 在PyCharm找到同样类似的 ...

  9. Android GUI架构之MVC模式

    1. Android UI框架 和其他Java UI框架一样,Android UI框架也是单线程和事件驱动的,采用MVC模式进行组织. 2. MVC模式 M:Model,是应用的核心,也就是应用真正想 ...

  10. hdu1281 棋盘游戏 二分图最大匹配

    小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决 ...