《Advanced .NET Debugging》 读书笔记 Listing 5-8: Fragmentation的简单示例
程序如下:
using System;
using System.Text;
using System.Runtime.InteropServices;namespace Advanced.NET.Debugging.Chapter5
{
class Fragment
{
static void Main(string[] args)
{
Fragment f = new Fragment();
f.Run(args);
}public void Run(string[] args)
{
if (args.Length < 2)
{
Console.WriteLine("05Fragment.exe <alloc. size> <max mem in MB>");
return;
}int size = Int32.Parse(args[0]);
int maxmem = Int32.Parse(args[1]);
byte[][] nonPinned = null;
byte[][] pinned = null;
GCHandle[] pinnedHandles = null;int numAllocs = maxmem * 1000000 / size;
pinnedHandles = new GCHandle[numAllocs];
pinned = new byte[numAllocs / 2][];
nonPinned = new byte[numAllocs / 2][];for (int i = 0; i < numAllocs / 2; i++)
{
nonPinned[i] = new byte[size];
pinned[i] = new byte[size];
pinnedHandles[i] =
GCHandle.Alloc(pinned[i], GCHandleType.Pinned);
}Console.WriteLine("Press any key to GC & promo to gen1");
Console.ReadKey();GC.Collect();
Console.WriteLine("Press any key to GC & promo to gen2");
Console.ReadKey();GC.Collect();
Console.WriteLine("Press any key to GC(free non pinned");
Console.ReadKey();for (int i = 0; i < numAllocs / 2; i++)
{
nonPinned[i] = null;
}GC.Collect();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
程序的关键就是GCHandle.Alloc这一句,可见在这一个for循环语句内,交替为pinned[]数组设置了Pinned类型的句柄,而nonPinned[]数组没有这种句柄。一旦设置以后,这样的对象在heap中不能移动位置。由于交替设置了nonPinned数组,所以会在Pinned数组元素的中间出现未利用的内存块,从而形成fragmentation。
1. 在命令行工具里执行 05fragment.exe 50000 1000 这个语句的意思是,分配1G大小的内存空间,每个数组的大小为50kB。
2. 打开WinDbg,attach到这个进程上。
3. 执行 .loadby sos.dll mscorwks
4. 执行 !DumpHeap –stat ,可见到此时内存分配的状况:
由于free的内存空间所占大小与heap总体积相比非常小,所以可以认为不存在fragment的问题。
5. 让程序继续运行,直到提示按任意键退出的时候,进入WinDbg,执行 !dumpheap –stat:
可见此时未利用的内存块的大小已经占到了heap的一半大小,此时fragment发生了。


浙公网安备 33010602011771号