问题描述
在浏览过的 PinnableObjectCache
从的mscorlib
,我遇到以下code
While browsing through the code of PinnableObjectCache
from mscorlib
, I've encountered the following code:
for (int i = 0; i < m_restockSize; i++)
{
// Make a new buffer.
object newBuffer = m_factory();
// Create space between the objects. We do this because otherwise it forms
// a single plug (group of objects) and the GC pins the entire plug making
// them NOT move to Gen1 and Gen2. By putting space between them
// we ensure that object get a chance to move independently (even if some are pinned).
var dummyObject = new object();
m_NotGen2.Add(newBuffer);
}
这让我知道什么是引用的插入的意思吗?虽然试着对内存中的对象,也不会在GC针为对象指定的具体地址?这是什么插入
行为实际上做什么,为什么是有必要的空出的对象之间?
It got me wondering what the reference to a plug means? While trying to pin an object in memory, wouldn't the GC pin the specific address specified for the object? What is this plug
behavior actually doing and why is there a need to "space out" between the objects?
推荐答案
好了,多次尝试获取来自人的内幕消息批复后,我决定尝试一点我自己。
Ok, so after several attempts to get official replies from people with "inside knowledge", i decided to experiment a little myself.
我试图做的是重新制作的场景,我有几个固定的对象和它们之间的一些非固定的对象(我使用了字节[]
)的试图创造一个在非固定的物体不动GC堆内的更高世代的影响。
What i tried to do is re-produce the scenario where i have a couple of pinned objects and some unpinned objects between them (i used a byte[]
) to try and create the effect where the unpinned objects don't move the a higher generation inside the GC heap.
在code跑到我的Intel酷睿i5的笔记本电脑,无论是在调试和发布运行Visual Studio 2015年的32位控制台应用程序中。我使用的WinDBG调试的code生活。
The code ran on my Intel Core i5 laptop, inside a 32bit console application running Visual Studio 2015 both in Debug and Release. I debugged the code live using WinDBG.
在code是相当简单:
The code is rather simple:
private static void Main(string[] args)
{
byte[] byteArr1 = new byte[4096];
GCHandle obj1Handle = GCHandle.Alloc(obj1, GCHandleType.Pinned);
object byteArr2 = new byte[4096];
GCHandle obj2Handle = GCHandle.Alloc(obj2, GCHandleType.Pinned);
object byteArr3 = new byte[4096];
object byteArr4 = new byte[4096];
object byteArr5 = new byte[4096];
GCHandle obj4Handle = GCHandle.Alloc(obj5, GCHandleType.Pinned);
GC.Collect(2, GCCollectionMode.Forced);
}
我开始了使用考虑看看在GC堆的地址空间 eeheap -gc
:
generation 0 starts at 0x02541018
generation 1 starts at 0x0254100c
generation 2 starts at 0x02541000
ephemeral segment allocation context: none
segment begin allocated size
02540000 02541000 02545ff4 0x4ff4(20468)
现在,我逐步完成code运行和手表为对象获得分配的:
Now, i step through the code running and watch as the objects get allocated:
0:000> !dumpheap -type System.Byte[]
Address MT Size
025424e8 72101860 4108
025434f4 72101860 4108
02544500 72101860 4108
0254550c 72101860 4108
02546518 72101860 4108
纵观地址,我可以看到他们都在当前第0代,因为它开始于 0x02541018
。我也看到,对象是使用固定gchandles
:
Looking at the addresses i can see they're all currently at generation 0 as it starts at 0x02541018
. I also see that the objects are pinned using !gchandles
:
Handle Type Object Size Data Type
002913e4 Pinned 025434f4 4108 System.Byte[]
002913e8 Pinned 025424e8 4108 System.Byte[]
现在,我通过code步骤,直到我得到它运行 GC.Collect的
的行:
Now, i step through the code untill i get to the line which runs GC.Collect
:
0:000> p
eax=002913e1 ebx=0020ee54 ecx=00000002 edx=00000001 esi=025424d8 edi=0020eda0
eip=0062055e esp=0020ed6c ebp=0020edb8 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
0062055e e80d851272 call mscorlib_ni+0xa28a70 (GC.Collect) (72748a70)
而现在,预测会发生什么,我检查GC发生地址,然后再使用 eeheap -gc
,我看到以下内容:!
And now, anticipating what happens, i check the GC generation address again using !eeheap -gc
and i see the following:
Number of GC Heaps: 1
generation 0 starts at 0x02547524
generation 1 starts at 0x0254100c
generation 2 starts at 0x02541000
的起始地址为0代已经从 0x02541018 为 0x02547524 。现在,我检查的地址固定,没有固定字节[]
目标:
The starting address for generation 0 has been moved from 0x02541018 to 0x02547524.Now, i check the address of the pinned and none pinned byte[]
objects:
0:000> !dumpheap -type System.Byte[]
Address MT Size
025424e8 72101860 4108
025434f4 72101860 4108
02544500 72101860 4108
0254550c 72101860 4108
02546518 72101860 4108
我看到他们的所有住在同一地址。 但是,事实生成0现在开始于 0x02547524 意味着他们都被提升到第1代。
And i see they are all stayed at the same address. But, the fact that generation 0 now starts at 0x02547524 means they've all been promoted to generation 1.
然后,我记得我读一些有关的书行为的 Pro的.NET性能的,它规定了以下内容:
Then, i remember i read something about that behavior in the book Pro .NET Performance, it states the following:
钉住对象prevents它被移动的垃圾 集电极。在代模型中,prevents推广寄托 两代人之间的对象。这是在尤其显著 年轻一代,如第0代,因为大小 0代是非常小的。这导致碎片固定的对象 第0代中有造成更多的伤害比它的潜力 可能会出现从检查固定之前我们介绍过几代人 入画面。 Fortunatly,CLR将具有促进能力 如果第0代就变成了:用以下伎俩固定的对象 严重分散,固定的对象,在CLR可以声明 第0代整个空间被认为是一个较高的生成和 从内存的一个新区域,将成为分配新对象 代0。这是通过改变短暂的业务实现。
和这实际上说明了我看到里面的WinDBG的行为。
And this actually explains the behavior i'm seeing inside WinDBG.
所以,最后直到任何人有任何其他的解释,我觉得评论是不正确的,不真正抓住了什么是真正发生在GC内部。如果任何人有任何详细说明,我会很高兴的补充。
So, to conclude and until anyone has any other explanation, i think the comment isn't correct and doesn't really capture what is really happening inside the GC. If anyone has anything to elaborate, i'd be glad to add.
这篇关于钉住对象时,GC行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!