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.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的托管内存占用。
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
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对象申请的托管内存已经被释放掉,
但非托管内存依然存在,内存在这里泄漏了!
这个工具还可以帮助我们计算出托管对象在堆中实际占用的内存大小,这也是一个很实用的功能,我们可以发现实际的占用大小
要比我们设计的大小略大,这是因为我们设计的类及其成员都是从一些基类中继承,这些基类的数据占用了一些内存造成。
到此如何跟踪基本.net应用的内存问题就介绍完毕。有时间再写写怎么跟踪ASP.NET应用的内存问题。
这一篇本来上午就要发出来,都快写完了,IE
崩溃!抓狂!