前言

一般来说.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的企业版才有这个功能。

https://blog.csdn.net/catshitone/article/details/79002823

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. 多路分支----switch语句

    switch-case与if-else有相似的作用,都是表达分支的方式. 语法形式: switch(type){ case 常量1: do something; break; case 常量2: do ...

  2. hbase数据原理及基本架构

    第一:hbase介绍 hbase是一个构建在hdfs上的分布式列存储系统: hbase是apache hadoop生态系统中的重要一员,主要用于海量结构化数据存储 从逻辑上讲,hbase将数据按照表. ...

  3. vue 验证电话

    <el-form :model="orderaddForm" :rules="rulesPhone" ref="orderaddForm&quo ...

  4. [LeetCode] Length of Longest Fibonacci Subsequence 最长的斐波那契序列长度

    A sequence X_1, X_2, ..., X_n is fibonacci-like if: n >= 3 X_i + X_{i+1} = X_{i+2} for all i + 2 ...

  5. [LeetCode] Maximize Distance to Closest Person 离最近的人的最大距离

    In a row of seats, 1 represents a person sitting in that seat, and 0 represents that the seat is emp ...

  6. 04.封装ajax

    <script> //封装ajax // 函数名 ajax // 函数的参数 // url: 请求的地址 // type: 请求的方式 get /post // data: 要上传的数据 ...

  7. 编写输出“Hello world”

    1.打开Eclipse---->点击文件 如图所示:   2. 然后在新建--->点击Java项目会出现下图框------>在项目名输入框中输入项目名并选择JRE----->点 ...

  8. python从入门到实践-11章测试模块(测试函数出问题)

    #!/user/bin/env python# -*- coding:utf-8 -*- # 用python中unittes中工具来测试代码 # 1.测试函数import unittestfrom n ...

  9. return和throw某些特性相似

    拷贝构造函数的调用拷贝构造函数会在以下三中情况下被调用(1)当类的一个对象去初始化该类的另一个对象时 int main(){ Point a(1,2); Point b(a);//用对象a初始化对象b ...

  10. [Swift]LeetCode696. 计数二进制子串 | Count Binary Substrings

    Give a string s, count the number of non-empty (contiguous) substrings that have the same number of ...