Sunday 15 August 2010

c# - GC behavior when pinning an object -



c# - GC behavior when pinning an object -

while browsing through code of pinnableobjectcache mscorlib, i've encountered next code:

for (int = 0; < m_restocksize; i++) { // create new buffer. object newbuffer = m_factory(); // create space between objects. because otherwise forms // single plug (group of objects) , gc pins entire plug making // them not move gen1 , gen2. putting space between them // ensure object chance move independently (even if pinned). var dummyobject = new object(); m_notgen2.add(newbuffer); }

it got me wondering reference plug means? while trying pin object in memory, wouldn't gc pin specific address specified object? plug behavior doing , why there need "space out" between objects?

ok, after several attempts official replies people "inside knowledge", decided experiment little myself.

what tried re-produce scenario have couple of pinned objects , unpinned objects between them (i used byte[]) seek , create effect unpinned objects don't move higher generation within gc heap.

the code ran on intel core i5 laptop, within 32bit console application running visual studio 2015 both in debug , release. debugged code live using windbg.

the code 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); }

i started out taking @ gc heap address space using !eeheap -gc:

generation 0 starts @ 0x02541018 generation 1 starts @ 0x0254100c generation 2 starts @ 0x02541000 ephemeral segment allocation context: none segment begin allocated size 02540000 02541000 02545ff4 0x4ff4(20468)

now, step through code running , watch objects 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

looking @ addresses can see they're @ generation 0 starts @ 0x02541018. see objects pinned using !gchandles:

handle type object size info type 002913e4 pinned 025434f4 4108 system.byte[] 002913e8 pinned 025424e8 4108 system.byte[]

now, step through code untill line 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 ei pl nz na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206 0062055e e80d851272 phone call mscorlib_ni+0xa28a70 (gc.collect) (72748a70)

and now, anticipating happens, check gc generation address 1 time again using !eeheap -gc , see following:

number of gc heaps: 1 generation 0 starts @ 0x02547524 generation 1 starts @ 0x0254100c generation 2 starts @ 0x02541000

the starting address generation 0 has been moved 0x02541018 0x02547524. now, check address of pinned , 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

and see all stayed @ same address. but, fact generation 0 starts @ 0x02547524 means they've been promoted generation 1.

then, remember read behavior in book pro .net performance, states following:

pinning object prevents beingness moved garbage collector. in generational model, prevents promotion of pinned objects between generations. important in younger generations, such generation 0, because size of generation 0 small. pinned objects cause fragmentation within generation 0 have potential of causing more harm might appear examining pinned before introduced generations the picture. fortunatly, clr has ability promote pinned objects using next trick: if generation 0 becomes severely fragmented pinned objects, clr can declare entire space of generation 0 considered higher generation , allocate new objects new part of memory become generation 0. achieved changing ephemeral segment.

and explains behavior i'm seeing within windbg.

so, conclude , until has other explanation, think comment isn't right , doesn't capture happening within gc. if has elaborate, i'd glad add.

c# .net garbage-collection .net-internals .net-4.6

No comments:

Post a Comment