如果大家经常看 LOH
堆上的对象布局时,会发现一个现象,那就是每一个大对象之前都有一个固定大小的 Free
块,接下来我们一起来探究下,首先上一段简单的代码:.
public class Program
{
public static void Main()
{
long[] num1 = new long[20000];
long[] num2 = new long[20000];
long[] num3 = new long[20000];
long[] num4 = new long[20000];
long[] num5 = new long[20000];
long[] num6 = new long[20000];
long[] num7 = new long[20000];
long[] num8 = new long[20000];
long[] num9 = new long[20000];
long[] num10 = new long[20000];
Console.ReadLine();
}
}
接下来我们用 windbg 看下 10 个大对象在 LOH 的布局。
0:009> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x02981018
generation 1 starts at 0x0298100C
generation 2 starts at 0x02981000
ephemeral segment allocation context: none
segment begin allocated committed allocated size committed size
02980000 02981000 02995D84 029A2000 0x14d84(85380) 0x21000(135168)
Large object heap starts at 0x03981000
segment begin allocated committed allocated size committed size
03980000 03981000 03B07B50 03B08000 0x186b50(1600336) 0x187000(1601536)
Pinned object heap starts at 0x04981000
04980000 04981000 04983220 04992000 0x2220(8736) 0x11000(69632)
Total Allocated Size: Size: 0x19daf4 (1694452) bytes.
Total Committed Size: Size: 0x1a8000 (1736704) bytes.
------------------------------
GC Allocated Heap Size: Size: 0x19daf4 (1694452) bytes.
GC Committed Heap Size: Size: 0x1a8000 (1736704) bytes.
0:009> !dumpheap 03981000 03B07B50
Address MT Size
03981000 00692c80 12 Free
03981010 00692c80 16 Free
03981020 05ca4b08 160012
039a8130 00692c80 16 Free
039a8140 05ca4b08 160012
039cf250 00692c80 16 Free
039cf260 05ca4b08 160012
039f6370 00692c80 16 Free
039f6380 05ca4b08 160012
03a1d490 00692c80 16 Free
03a1d4a0 05ca4b08 160012
03a445b0 00692c80 16 Free
03a445c0 05ca4b08 160012
03a6b6d0 00692c80 16 Free
03a6b6e0 05ca4b08 160012
03a927f0 00692c80 16 Free
03a92800 05ca4b08 160012
03ab9910 00692c80 16 Free
03ab9920 05ca4b08 160012
03ae0a30 00692c80 16 Free
03ae0a40 05ca4b08 160012
Statistics:
MT Count TotalSize Class Name
00692c80 11 172 Free
05ca4b08 10 1600120 System.Int64[]
Total 21 objects
可以看到每一个大对象前面都有一个 16 byte
的FREE块,那为什么是 16byte呢,这是因为32bit进程预留了 4*4byte
大小,在 64bit 平台上是 4*8=32byte
,接下来可以用 dc 看下 free 块的内容。
0:009> dc 03ae0a30
03ae0a30 00692c80 00000004 00000000 00000000 .,i.............
算是清零内容,那free块有什么用呢?主要还是 GC 回收的 计划阶段
时用于模拟压缩用的 Plug 信息,存放 reloc 地址值。
如果你把 long[20000]
改成 long[2]
的时候,你会发现这 10 个 long[2]
都是紧凑在一块的。
0:000> !dumpheap 0285acac 0285ada8
Address MT Size
0285acac 05ca4b08 28
0285acc8 05ca4b08 28
0285ace4 05ca4b08 28
0285ad00 05ca4b08 28
0285ad1c 05ca4b08 28
0285ad38 05ca4b08 28
0285ad54 05ca4b08 28
0285ad70 05ca4b08 28
0285ad8c 05ca4b08 28
0285ada8 05ca4b08 28
Statistics:
MT Count TotalSize Class Name
05ca4b08 10 280 System.Int64[]
Total 10 objects