Deep Dumpster DivingA close look at .Net garbage collectionRonn BlackOctober 2009
Why should I care?
Demo 1 (Word Count)using System;usingSystem.Collections.Generic;usingSystem.Diagnostics;using System.IO;publicclassMyClass{	publicstaticvoidRunSnippet()	{		while(true)		{				Stopwatch watch = new Stopwatch();watch.Start();StreamReadersr = newStreamReader(@"C:\Users\Ronn\Documents\My Code Snippets\Garbage Collection\catcher.txt");				string text = sr.ReadToEnd();intwordCount = text.Split().Length;Console.WriteLine("{0} Words", wordCount);watch.Stop();Console.WriteLine(watch.ElapsedMilliseconds + " Milliseconds");		}	}
using System;usingSystem.Collections.Generic;usingSystem.Threading;usingSystem.Runtime.CompilerServices;publicclassMyClass{	static Byte[] bytes;	publicstaticvoidRunSnippet()	{		Timer tmr = new Timer(M, null, 0, 1000);Thread.Sleep(20);		for(int i = 0; i < 1000; i++)			bytes = new Byte[2000];Console.ReadLine();	}	staticvoid M(object state)	{Console.WriteLine("M - " + DateTime.Now);	}Demo 2
Unmanaged Memory Management
Hi AddressUnused AreaUnused AreaArgs & VariablesStackStack PointerHeapReservedLow Address
NextObjPtr
NextObjPtr
RootsNextObjPtr
NextObjPtrRoots
Finalizers=~MyClass(){	//Do work here…}MyClass.Finalize(){	//Do work here…}
RootsFinalization QueueIIHFGEFCEFreachable QueueDCBA
RootsFinalization QueueI (x)I (x)H (x)FG (x)E (x)FCE (x)Freachable QueueDCB (x)A
RootsFinalization QueueFI (x)CFFreachable QueueE (x)DCI (x)AE (x)
OptimizationsGenerationsNewly created objects tend to have short lives.The older an object is, the longer it will survive. Groups objects by age and collects younger objects more frequently than older objects.All objects added to heap are in generation 0.When an object survives the first garbage collection it is promoted to generation 1.When garbage collection is triggered survivors from generation 1 are promoted to generation 2 and generation 0 survivors are promoted to gen 1.As objects "mature", they are moved to the next older generation until they reach gen 2.
using System;usingSystem.Collections.Generic;usingSystem.Threading;usingSystem.Runtime.CompilerServices;publicclassMyClass{	static Byte[] bytes;	publicstaticvoidRunSnippet()	{		Timer tmr = new Timer(M, null, 0, 1000);Thread.Sleep(20);		for(int i = 0; i < 1000; i++)			bytes = new Byte[2000];Console.ReadLine();	}	staticvoid M(object state)	{Console.WriteLine("M - " + DateTime.Now);	}Demo 3 – WTF??
Demo 4 (CLR Profile Word Count)using System;usingSystem.Collections.Generic;usingSystem.Diagnostics;using System.IO;publicclassMyClass{	publicstaticvoidRunSnippet()	{		while(true)		{				Stopwatch watch = new Stopwatch();watch.Start();StreamReadersr = newStreamReader(@"C:\Users\Ronn\Documents\My Code Snippets\Garbage Collection\catcher.txt");				string text = sr.ReadToEnd();intwordCount = text.Split().Length;Console.WriteLine("{0} Words", wordCount);watch.Stop();Console.WriteLine(watch.ElapsedMilliseconds + " Milliseconds");		}	}
IDisposablepublic class MyClass : IDisposable{public void Dispose()	{		Dispose(true);GC.SuppressFinalize(this);	}protected virtual void Dispose(bool disposing)	{if (!disposed)		{if (disposing)			{// Dispose managed resources. Ex:	Components.Dispose();			}// Release ONLY unmanaged resources. Ex:	CloseHandle(handle);		}		disposed = true;	}protected volatile bool disposed = false;	~MyClass()      	{		Dispose(false);	}}[ComVisible(true)]public interface IDisposable{	void Dispose();}
Usingusing System;using System.Collections.Generic;using System.Diagnostics;
Usingusing System;using System.Collections.Generic;using System.Diagnostics;using (MyClass c = new MyClass()){//Do Some Work}
Demo 5 - optimizeusing System;using System.Collections.Generic;using System.Diagnostics;using System.IO;public class MyClass{	public static void RunSnippet()	{		while(true)		{			Stopwatch watch = new Stopwatch();watch.Start();			using(StreamReadersr = new StreamReader(@"C:…Garbage Collection\catcher.txt"))			{				string line = "";intwordCount = 0;				while((line = sr.ReadLine()) != null)				{wordCount += line.Split().Length;				}Console.WriteLine("{0} Words", wordCount);			}watch.Stop();Console.WriteLine(watch.ElapsedMilliseconds + " Milliseconds");		}	}
TotalRelocatedFinal	Gen 0 	Gen 1	Large Object Heap6,578,038	96,608	5,057,272	1,400,580	12	3,535,4645,473,972	101,501	1,441,201	2,097,172	103,992	9,328========	========	========	=========	========	===========	-1,104,066	+4,893	-3,617,071	+696,592	+103,980	-3,526,136
Types of Memory LeaksManaged leaks – persistent object holds a reference to an object expected to be garbage collected.Unmanaged leaks  - using unmanaged resources, dll’s or COM objects that leak memory.
Demo 7 - Leaky program?
 public partial class ChildForm : Form    {        public ChildForm()        {InitializeComponent();        }        private void ChildForm_Load(object sender, EventArgs e)        {Program.Skin.PropertyChanged += new 			PropertyChangedEventHandler(Skin_PropertyChanged);        }        void Skin_PropertyChanged(object sender, PropertyChangedEventArgs e)        {this.BackColor = Program.Skin.BackgroundColor;            this.label1.ForeColor = Program.Skin.ForegroundColor;        }    }
 public partial class ChildForm : Form    {        public ChildForm()        {InitializeComponent();        }        private void ChildForm_Load(object sender, EventArgs e)        {Program.Skin.PropertyChanged += new 			PropertyChangedEventHandler(Skin_PropertyChanged);        }        void Skin_PropertyChanged(object sender, PropertyChangedEventArgs e)        {this.BackColor = Program.Skin.BackgroundColor;            this.label1.ForeColor = Program.Skin.ForegroundColor;        }			protected override void OnClosing(CancelEventArgs e)        		{base.OnClosing(e);Program.Skin.PropertyChanged -= Skin_PropertyChanged;        		}    }
Contact & Reference MaterialRonn Black  rblack@btsoft.orghttp://msdn.microsoft.com/en-us/library/ms973837.aspx (Garbage Collector Basics and Performance Hints)http://www.microsoft.com/downloads/details.aspx?FamilyID=a362781c-3870-43be-8926-862b40aa0cd0&DisplayLang=enCLR Profiler for .Net 2.0http://www.openasthra.com/multithreading/heap-overview/ Heap Overviewhttp://74.125.155.132/search?q=cache:44hDjSztDf4J:doc.bughunter.net/buffer-overflow/advanced-malloc-exploits.html+malloc+overview&cd=21&hl=en&ct=clnk&gl=us Advanced Malloc exploitshttp://msdn.microsoft.com/en-us/magazine/cc534993.aspxhttp://www.microsoft.com/downloads/details.aspx?FamilyId=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en CLR Profiler

Deep Dumpster Diving

  • 1.
    Deep Dumpster DivingAclose look at .Net garbage collectionRonn BlackOctober 2009
  • 2.
  • 3.
    Demo 1 (WordCount)using System;usingSystem.Collections.Generic;usingSystem.Diagnostics;using System.IO;publicclassMyClass{ publicstaticvoidRunSnippet() { while(true) { Stopwatch watch = new Stopwatch();watch.Start();StreamReadersr = newStreamReader(@"C:\Users\Ronn\Documents\My Code Snippets\Garbage Collection\catcher.txt"); string text = sr.ReadToEnd();intwordCount = text.Split().Length;Console.WriteLine("{0} Words", wordCount);watch.Stop();Console.WriteLine(watch.ElapsedMilliseconds + " Milliseconds"); } }
  • 5.
    using System;usingSystem.Collections.Generic;usingSystem.Threading;usingSystem.Runtime.CompilerServices;publicclassMyClass{ static Byte[]bytes; publicstaticvoidRunSnippet() { Timer tmr = new Timer(M, null, 0, 1000);Thread.Sleep(20); for(int i = 0; i < 1000; i++) bytes = new Byte[2000];Console.ReadLine(); } staticvoid M(object state) {Console.WriteLine("M - " + DateTime.Now); }Demo 2
  • 6.
  • 7.
    Hi AddressUnused AreaUnusedAreaArgs & VariablesStackStack PointerHeapReservedLow Address
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
    RootsFinalization QueueI (x)I(x)H (x)FG (x)E (x)FCE (x)Freachable QueueDCB (x)A
  • 19.
  • 20.
    OptimizationsGenerationsNewly created objectstend to have short lives.The older an object is, the longer it will survive. Groups objects by age and collects younger objects more frequently than older objects.All objects added to heap are in generation 0.When an object survives the first garbage collection it is promoted to generation 1.When garbage collection is triggered survivors from generation 1 are promoted to generation 2 and generation 0 survivors are promoted to gen 1.As objects "mature", they are moved to the next older generation until they reach gen 2.
  • 21.
    using System;usingSystem.Collections.Generic;usingSystem.Threading;usingSystem.Runtime.CompilerServices;publicclassMyClass{ static Byte[]bytes; publicstaticvoidRunSnippet() { Timer tmr = new Timer(M, null, 0, 1000);Thread.Sleep(20); for(int i = 0; i < 1000; i++) bytes = new Byte[2000];Console.ReadLine(); } staticvoid M(object state) {Console.WriteLine("M - " + DateTime.Now); }Demo 3 – WTF??
  • 22.
    Demo 4 (CLRProfile Word Count)using System;usingSystem.Collections.Generic;usingSystem.Diagnostics;using System.IO;publicclassMyClass{ publicstaticvoidRunSnippet() { while(true) { Stopwatch watch = new Stopwatch();watch.Start();StreamReadersr = newStreamReader(@"C:\Users\Ronn\Documents\My Code Snippets\Garbage Collection\catcher.txt"); string text = sr.ReadToEnd();intwordCount = text.Split().Length;Console.WriteLine("{0} Words", wordCount);watch.Stop();Console.WriteLine(watch.ElapsedMilliseconds + " Milliseconds"); } }
  • 29.
    IDisposablepublic class MyClass: IDisposable{public void Dispose() { Dispose(true);GC.SuppressFinalize(this); }protected virtual void Dispose(bool disposing) {if (!disposed) {if (disposing) {// Dispose managed resources. Ex: Components.Dispose(); }// Release ONLY unmanaged resources. Ex: CloseHandle(handle); } disposed = true; }protected volatile bool disposed = false; ~MyClass() { Dispose(false); }}[ComVisible(true)]public interface IDisposable{ void Dispose();}
  • 30.
  • 31.
    Usingusing System;using System.Collections.Generic;usingSystem.Diagnostics;using (MyClass c = new MyClass()){//Do Some Work}
  • 32.
    Demo 5 -optimizeusing System;using System.Collections.Generic;using System.Diagnostics;using System.IO;public class MyClass{ public static void RunSnippet() { while(true) { Stopwatch watch = new Stopwatch();watch.Start(); using(StreamReadersr = new StreamReader(@"C:…Garbage Collection\catcher.txt")) { string line = "";intwordCount = 0; while((line = sr.ReadLine()) != null) {wordCount += line.Split().Length; }Console.WriteLine("{0} Words", wordCount); }watch.Stop();Console.WriteLine(watch.ElapsedMilliseconds + " Milliseconds"); } }
  • 34.
    TotalRelocatedFinal Gen 0 Gen1 Large Object Heap6,578,038 96,608 5,057,272 1,400,580 12 3,535,4645,473,972 101,501 1,441,201 2,097,172 103,992 9,328======== ======== ======== ========= ======== =========== -1,104,066 +4,893 -3,617,071 +696,592 +103,980 -3,526,136
  • 35.
    Types of MemoryLeaksManaged leaks – persistent object holds a reference to an object expected to be garbage collected.Unmanaged leaks - using unmanaged resources, dll’s or COM objects that leak memory.
  • 39.
    Demo 7 -Leaky program?
  • 45.
    public partialclass ChildForm : Form { public ChildForm() {InitializeComponent(); } private void ChildForm_Load(object sender, EventArgs e) {Program.Skin.PropertyChanged += new PropertyChangedEventHandler(Skin_PropertyChanged); } void Skin_PropertyChanged(object sender, PropertyChangedEventArgs e) {this.BackColor = Program.Skin.BackgroundColor; this.label1.ForeColor = Program.Skin.ForegroundColor; } }
  • 46.
    public partialclass ChildForm : Form { public ChildForm() {InitializeComponent(); } private void ChildForm_Load(object sender, EventArgs e) {Program.Skin.PropertyChanged += new PropertyChangedEventHandler(Skin_PropertyChanged); } void Skin_PropertyChanged(object sender, PropertyChangedEventArgs e) {this.BackColor = Program.Skin.BackgroundColor; this.label1.ForeColor = Program.Skin.ForegroundColor; } protected override void OnClosing(CancelEventArgs e) {base.OnClosing(e);Program.Skin.PropertyChanged -= Skin_PropertyChanged; } }
  • 47.
    Contact & ReferenceMaterialRonn Black rblack@btsoft.orghttp://msdn.microsoft.com/en-us/library/ms973837.aspx (Garbage Collector Basics and Performance Hints)http://www.microsoft.com/downloads/details.aspx?FamilyID=a362781c-3870-43be-8926-862b40aa0cd0&DisplayLang=enCLR Profiler for .Net 2.0http://www.openasthra.com/multithreading/heap-overview/ Heap Overviewhttp://74.125.155.132/search?q=cache:44hDjSztDf4J:doc.bughunter.net/buffer-overflow/advanced-malloc-exploits.html+malloc+overview&cd=21&hl=en&ct=clnk&gl=us Advanced Malloc exploitshttp://msdn.microsoft.com/en-us/magazine/cc534993.aspxhttp://www.microsoft.com/downloads/details.aspx?FamilyId=A362781C-3870-43BE-8926-862B40AA0CD0&displaylang=en CLR Profiler

Editor's Notes

  • #2 IntroductionThis is my first time doing this and I’m sure I’ll muck things up somewhere along the way. I don’t consider myself an expert on this subject. I simply have done enough investigation in this area to have some interesting insights on the subject.
  • #3 Why should I care?After all one of the reasons you chose a managed environment is to forget about memory management. You pay a price for garbage collection. Bad algorithms cause the garbage collector to work harder. Simple program, Count the number of words in a document using string.Split() and then get the length of the array.
  • #5 This program is spending about 20 to 50% of its time just trying to manage the memory. Paying attention to memory can give even a small program a 20 to 50% performance boost. More efficient alternatives later for now just understand it creates a lot of objects and throws them away. In this run there were 2 peaks that reached a little over 70%.
  • #8 The stack is where local variables are allocated.The heap is where malloc and new allocate space.
  • #9 As programs request memory the system allocates it from the heap.
  • #12 As programs release memory open spots appear in the heap. Eventually this area becomes fragmented and the system has to search through a list of free space to find enough space for the memory requested. The more fragmented memory becomes the longer this can take.
  • #13 .Net reserves a contiguous region of memory that it will use for the managed heap.Frameworkalso maintains a pointer to the location where the next object will be allocated.
  • #14 Application creates some objects. If it will fit the location the NewObjPtr points to is used for the new object, the constructor of the new object is called and the address of the object is returned to the calling program.NewObjPtr is advanced beyond the new object and points to where the next object will be created in the heap.