.net 框架号称永远不会发生内存泄漏,原因是其引入了内存回收的机制。但实际应用中,往往我们分配了对象但没有释放指向该对象的引用,导致对象永远无法释放。最常见的情况就是给对象添加了事件处理函数,但当不再使用该对象时却没有将该函数从对象的事件handler中减掉。另外如果分配了非托管内存,而没有手工释放,GC同样无能为力。所以当.net应用发生内存泄漏后如何跟踪应用的内存使用情况,定位到程序设计中的缺陷显得非常重要。本文将介绍通过.NET Memory Profiler来跟踪.net应用的内存泄漏,为定位.net应用内存问题提供一个解决途径。

.NET Memory Profiler是一款强大的.net 内存跟踪和优化工具。该工具目前可以对一下4种.net应用进行内存跟踪。

  • 基本应用 例如winform, console application等

  • ASP.net 应用

  • WPF应用

  • Window 服务

本篇将通过对以下三种内存的跟踪来阐述如何使用该工具对基本.net应用程序进行内存的跟踪。三种内存包括:

  • 托管内存

  • 线程托管内存

  • 非托管内存

在开始之前,先需要建立环境。
       我采用.NET Memory Profiler V3.1.307 版本进行测试。安装完后需要新建一个项目,由于我们需要测
.net基本应用,所以新建项目时选择Standalone application. 点击next后,输入要测试的.net 应用的路径和参数。
然后按下 finish.项目就建立完成了。

测试程序是我编写的,编译后生成TestMemorySize.exe 这个控制台应用程序。下载地址

代码如下

主程序等待用户输入,输入m,t,u 分别是增加托管内存,创建一个自动增加托管内存的线程,增加非托管内存。
输入d,释放主线程创建的托管内存对象。

using System;
using System.Collections.Generic;
using System.Text;

namespace TestMemorySize
{
    class Program
    {
        static void Main(string[] args)
        {
            MemoryInc memoryInc = new MemoryInc();

while (true)
            {
                long memorysize = System.Diagnostics.Process.GetCurrentProcess().PagedMemorySize64;

Console.WriteLine(string.Format("PagedMemorySize:{0}MB", memorysize / (1024*1024)));
                Console.WriteLine(string.Format("ManagedMemIncTimes:{0}", memoryInc.ManagedMemIncTimes));
                Console.WriteLine(string.Format("UnmanagedMemIncTimes:{0}", memoryInc.UnmanagedMemIncTimes));

String cmd = Console.ReadLine();

switch (cmd)
                {
                    case "d":
                        memoryInc = new MemoryInc();
                        GC.Collect();
                        break;
                    case "m":
                        memoryInc.IncManagedMemory();
                        break;
                    case "u":
                        memoryInc.IncUnmanagedMemory();
                        break;
                    case "t":
                        MemoryLeakThread thread = new MemoryLeakThread();
                        break;
                    case "l":
                        break;
                }
            }
        }
    }
}

MemoryInc 是一个增加托管内存和非托管内存的类。

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace TestMemorySize
{
    class MemoryInc
    {
        int _ManagedMemIncTimes = 0;
        int _UnmanagedMemIncTimes = 0;

List<byte[]> _ManagedMemory = new List<byte[]>();
        LinkedList<IntPtr> _UnmanagedMemory = new LinkedList<IntPtr>();

/// <summary>
        /// Managed memory increase times
        /// </summary>
        public int ManagedMemIncTimes
        {
            get
            {
                return _ManagedMemIncTimes;
            }
        }

/// <summary>
        /// Unmanaged memory increase times
        /// </summary>
        public int UnmanagedMemIncTimes
        {
            get
            {
                return _UnmanagedMemIncTimes;
            }
        }

/// <summary>
        /// Increase managed memory
        /// </summary>
        public void IncManagedMemory()
        {
            _ManagedMemIncTimes++;

_ManagedMemory.Add(new byte[1024 * 1024 * _ManagedMemIncTimes]);
        }

/// <summary>
        /// Increase unmanaged memory
        /// </summary>
        public void IncUnmanagedMemory()
        {
            _UnmanagedMemIncTimes++;

_UnmanagedMemory.AddLast(Marshal.AllocCoTaskMem(1024 * 1024 * _UnmanagedMemIncTimes));
        }
    }
}

MemoryLeakThread 这个线程没30秒增加1M的托管内存占用。


using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TestMemorySize
{
    class MemoryLeakThread
    {
        Thread _Thread;
        byte[] _Buf;
        int _Times = 0;

private void ThreadProc()
        {
            while (true)
            {
                _Times++;
                _Buf = new byte[_Times * 1024 * 1024];
                Thread.Sleep(30 * 1000);
            }
        }

public MemoryLeakThread()
        {
            _Thread = new Thread(new ThreadStart(ThreadProc));
            _Thread.IsBackground = true;
            _Thread.Start();
        }
    }
}

准备就绪,下面就开始体验了。

1、托管内存的跟踪
       菜单中选择Profiler->Start 启动TestMemorySize.exe,然后输入m 并回车,这是分配了1M的托管内存。
在菜单中选择Profiler->Collect Heap Shapshot. 这是就可以看到堆中的所有对象了。

从这个界面我们看到虽然列出了对象的列表,但只有类型和大小等信息,却没有对象的名称以及分配过程
信息,这样怎么定位那块内存没有被释放啊?不要着急,.NET Memory Profiler还是比较强大的,让我们继续往下
前进。

双击选中的对象后进入对象所占用的堆的详细信息

再双击选中行,这时我们就可以看到对象的名称和分配堆栈的情况了。是不是很兴奋?终于找到是哪个家伙在捣蛋了。

2、线程中创建的托管内存的跟踪
       线程中创建的托管内存跟踪方法和第1节介绍的方法基本是一样的。启动TestMemorySize.exe后输入t 并回车,创建一个
吃内存的线程。下面步骤都相同了。

3、非托管内存的跟踪
       要跟踪非托管内存需要做一个设置:选择菜单中view->Project Property Pages,按下图进行设置。

设置好后启动TestMemorySize.exe后输入u 并回车,创建1M的非托管内存。下面步骤相同。

非托管内存无法看到对象的名称,但可以看到内存的申请过程,这对于定位内存问题已经提供了很大的帮助。

现在我们再输入m 回车,创建1M的托管内存,然后输入d 回车,这时我们可以发现memoryInc对象申请的托管内存已经被释放掉,
但非托管内存依然存在,内存在这里泄漏了!

这个工具还可以帮助我们计算出托管对象在堆中实际占用的内存大小,这也是一个很实用的功能,我们可以发现实际的占用大小
要比我们设计的大小略大,这是因为我们设计的类及其成员都是从一些基类中继承,这些基类的数据占用了一些内存造成。

本文转自 yuanzhitang 51CTO博客,原文链接:http://blog.51cto.com/yuanzhitang/1882170,如需转载请自行联系原作者

用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇相关推荐

  1. 用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇(转载)

    用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇 作者:肖波       .net 框架号称永远不会发生内存泄漏,原因是其引入了内存回收的机制.但实际应用中, ...

  2. 使用 .Net Memory Profiler 诊断 .NET 应用内存泄漏(方法与实践)

    使用 .Net Memory Profiler 诊断 .NET 应用内存泄漏(方法与实践) 博客分类: Troubleshooting & tuning .netASP.netLoadrunn ...

  3. Android内存分析工具:Memory Profiler

    一.前言  我们知道,Android系统检测到app有不再使用对象时,就会进行内存回收相关的工作. 尽管Android检测无用对象.回收内存的方法在不断改进,  但在目前所有的Android版本中,进 ...

  4. android studio dump java heap_Android Studio 3.0 Memory Profiler使用

    Memory Profiler是Android Profiler中的一个组件,Android Profiler是Android Studio3.0用来替换之前Android Monitor的观察工具, ...

  5. Android Studio 性能优化工具 - Profiler、CPU Profiler、Memory Profiler、Netwrok Profiler、Evengy Profiler 详解

    关于性能优化的问题,可能一直有遇到,也一直在解决,但是在中小厂和自我要求不严格的场景下,我们很少去实实在在的做性能优化: 在性能优化中我们通常会通过自己的经验或工具来发现问题,本想着能短时间内搞定Pr ...

  6. 使用Memory Analyzer tool(MAT)分析内存泄漏(一)

    使用Memory Analyzer tool(MAT)分析内存泄漏(一) (2010年05月21日) 发表于 Java博客 前言的前言 :本文是自 2005 年 8 月以来,首次在一个月之内发布三篇文 ...

  7. 【Android 内存优化】使用 Memory Analyzer ( MAT ) 工具分析内存 ( MAT 工具使用 | 最大对象 | 类实例个数 | 引用与被引用 | GC Roots 最短链 )

    文章目录 一. 内存中最大的对象 二. 查看每个类的对象实例的个数 三. 查看对象的引用与被引用 四. 查看对象到 GC Roots 的最短距离 1. 选择 Merge Shortest Paths ...

  8. 使用Memory Analyzer tool(MAT)分析内存泄漏

    http://www.blogjava.net/rosen/archive/2010/05/21/321575.html http://www.blogjava.net/rosen/archive/2 ...

  9. [iOS]Advanced Memory Management Programming Guide 高级内存管理编程指南(官方文档翻译)

    Advanced Memory Management Programming Guide - 高级内存管理编程指南(官方文档翻译) 版权声明:本文为博主原创翻译,如需转载请注明出处. 新博客文章地址: ...

最新文章

  1. 神经网络的演变与发展(Part 2)
  2. JavaScript语言标准
  3. php中处理xml文件的类 simpleXML
  4. Nginx-08:Nginx配置高可用
  5. HTML和CSS初级前端面试题汇总(持续补充)
  6. java native方法_并发系列-native函数回调Java方法原理实践
  7. 菜鸟做HTML5小游戏 - 刮刮乐
  8. 判断小数是否相等_五年级上册数学综合练习题(填空、判断、选择、文字题),覆盖全册知识点!...
  9. Java修炼之路——基础篇——数据类型
  10. 机器学习性能评估指标(综合性总结)
  11. Python 线程队列 LifoQueue – LIFO - Python零基础入门教程
  12. 倒计时按钮_办公小技巧:轻松玩转PPT秒针倒计时
  13. (python)查看糗事百科文字 点赞 作者 等级 评论
  14. Adblock Plus无法屏蔽CSDN右下角广告解决
  15. 金融创新推动资产管理公司发展
  16. Linux 卸载及删除磁盘分区
  17. android 锁屏应用,推荐几款好用的安卓(Android)手机锁屏软件
  18. c语言 英文歌曲大赛,英文歌曲大赛活动方案
  19. PySpark数据分析教程(转载)
  20. Kotlin笔记27--使用Intent传递数据

热门文章

  1. AI一分钟 | 华为余承东携Mate 10高调亮相CES,不惧美国运营商放鸽子;日本推“手掌支付”服务,竟靠手相和手掌静脉识别
  2. 手撕面试题:多个线程交替打印问题
  3. 面经:为了拿到字节跳动offer,鬼知道我经历了啥...
  4. 职场老鸟的焦虑与出路
  5. Java分布式 RPC 框架性能大比拼,Dubbo最差?
  6. 推荐100份:高并发高可用和中台一网打尽
  7. 初入职场的我怎么就成了个打杂的,我是这样破局的 No.146
  8. 关于计算机读研的小建议
  9. 是什么让数据科学家从优秀变得伟大?
  10. 登顶CLUE榜单,腾讯云小微与腾讯AI Lab联合团队提出基于知识的中文预训练模型...