.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,释放主线程创建的托管内存对象。

Code
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 是一个增加托管内存和非托管内存的类。

Code
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的托管内存占用。

Code
MemoryLeakThread
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();
}
}
}
准备就绪,下面就开始体验了。
(文/肖波 出处/http://www.cnblogs.com/eaglet/)
您可能对 [Visual Studio.NET] 的这些文章也感兴趣: