410 likes | 504 Views
5 Misconceptions about .NET Memory Management Wednesday June 1 st 2011 Clive Tong and A ndrew Hunter. Your presenters. Developer, .NET Reflector. Developer, ANTS Memory Profiler. The webinar. Clive : 5 misconceptions about .NET memory management (30 mins )
E N D
5 Misconceptions about .NET Memory Management Wednesday June 1st 2011 Clive Tong and Andrew Hunter
Your presenters Developer, .NET Reflector Developer, ANTS Memory Profiler
The webinar • Clive: 5 misconceptions about .NET memory management (30 mins) • Andrew: Q&A session for any questions to do with .NET memory • $50 Amazon voucher for the best answer to Clive’s question. • Please type questions into your GoToWebinar chat box
Some Misconceptions About Memory Management in .NET Clive TongRed Gate Software
Five misconceptions 1 A garbage collector collects garbage 2 Doing lots of gen0 collections is bad 3 Performance counters are great for understanding what is happening 4 .NET doesn’t leak memory 5 All objects are treated the same
1) The Garbage Collectors Collect Garbage • The focus is really on the non-garbage • Most (young) objects die young • Designed to collect dead items without processing them individually • Note this is for generation 0
A simple mutator var collect = new List<B>();while(true){collect.Add(new A());new A(); new A();}
Allocation in generation 0 Generation 0 After one iteration of the while loop As we go into the fourth iteration
No space, so copy Promote gen0 gen1
Fix-up gen0 gen1
And recycle gen0 gen1
Observations • Trick is that objects are allowed to move • Need to get to a safe point when pointers can be fixed • Additionally this allows quick allocation
Fast allocation 0:000> u 002c2020 moveax,dwordptr [ecx+4] movedx,dwordptrfs:[0E40h] add eax,dwordptr [edx+48h] cmpeax,dwordptr [edx+4Ch] ja 002c203b movdwordptr [edx+48h],eax sub eax,dwordptr [ecx+4] movdwordptr [eax],ecx ret002c203b: jmpclr!JIT_NewFast(5cbded01)
Solution • Avoid locking too frequently by having thread specific allocation buffers Thread 1 allocation buffer Thread 2 allocation buffer
And there is one other trick • Use generations to focus attention– 0,1,2 • Need to track object references 0:000> u 5cbc2fb0 clr!JIT_WriteBarrierEAX: movdwordptr [edx],eax cmpeax,271100Ch jbclr!JIT_WriteBarrierEAX+0x17 (5cbc2fc7) shredx,0Ah nop cmpbyte ptr [edx+0BD63E0h],0FFh jneclr!JIT_WriteBarrierEAX+0x1a (5cbc2fca) ret clr!JIT_WriteBarrierEAX+0x18: nop nop movbyte ptr [edx+0BD63E0h],0FFh ret
2) Lots of gen0 collections is bad • We have covered this already • Time proportional to live data • Though with (fixed) overheads • Worse case double allocation
3) Performance counters are accurate • Quick demonstration
Periodic measurements • It’s important to remember that these are updated when a collection happens • No collection means the counter is stuck • The average value can be misleading
class Program { static void Main(string[] args) { var accumulator = new List<Program>(); while (true) { DateTime start = DateTime.Now; while ((DateTime.Now - start).TotalSeconds < 15) { accumulator.Add(new Program()); Thread.Sleep(1); } Console.WriteLine(accumulator.Count); } }}
4) .NET doesn’t leak • It’s a question of definition • Old definition -Forgot to de-allocate after use -Lost the final pointer to some memory -Forgot your responsibilities
New definition • Premature release was often fatal • Those days are gone (*) • The runtime is ultra-cautious • It’s difficult to have an effective cost model (*) except when you aggressively dispose
What makes things live longer? • Runtime • User • Library • Compiler
Runtime • Type of build • Having a debugger attached • Heuristics choosing when to collect higher generations • Finalizers
User • Event handlers • Assigning temporary values to fields • Value only needed on some code paths
Library • Caches without a lifetime policy • Data binding
Compiler • Closures
Closures class Program { private static Func<int> s_LongLived; static void Main(string[] args) { var x = 20; var y = new int[20200]; Func<int> getSum = () => x + y.Length; Func<int> getFirst = () => x; s_LongLived = getFirst; } }
5) All objects are created equal • Copying takes a while • Need a better way to handle large objects • Resort to standard mark-and-sweep • No compact at the moment
No copying during collection Before After
Some observations • No movement, so no fix-ups • Potential parallelism • But potential fragmentation • Only do when gen2 is collected • Temporary large objects don’t fit model • All blocks are touched
The problem of fragmentation Before collection After collection Allocate block of this size: Next allocation
Conclusion • There’s a lot going on inside your process heap • The only way to really understand what is going on is to use tools to visualize things
Q&A Session • Please type your questions into the GoToWebinar box • We will read out your questions for Andrew to answer
Thank you! • A recording of this webinar will be emailed to you tomorrow • Do get in touch!