Blog Post Revised 12/13/2010
SharePoint Server development has some gotchas with serious implications that every application developer needs to be intimately familiar with before deploying into production farms. In particular, Microsoft.SharePoint.SPSite , Microsoft.SharePoint.SPWeb , and the often overlooked Microsoft.SharePoint.Publishing objects need to be carefully examined and disposed of properly in order to avoid potential memory leaks. My original objective with this blog post was to consolidate several different reliable sources compiled by Microsoft's top Subject Matter Experts (SME’s) into a Uber-Dispose quick reference which could be used to increase developer awareness of the current Microsoft Guidance. I’ve been working closely with the SharePoint Product Group as well as the top Microsoft Support and Services SME’s to help carve out the information you see here. I plan to keep this blog post updated with the latest official guidance from Microsoft and while there are more verbose resources available elsewhere the primary objective is to provide lots of samples in a quick reference format. Pre-requisites: The intended audience for this guidance is a seasoned .NET developer who currently is or will be developing custom SharePoint solutions with Visual Studio.
- SPDisposeCheck automated Dispose() code review tool updated version 14.0.4762.1000 released 12/13/2010
- MSDN : Best Practices: Using Disposable Windows SharePoint Services Objects
- MSDN : Best Practices: Common Coding Issues When Using the SharePoint Object Model
Quick Reference - SharePoint Example Dispose() Patterns
- WSS 3.0
- Microsoft.SharePoint.SPList.BreakRoleInheritance() method
- Microsoft.SharePoint.SPSite new() operator
- Microsoft.SharePoint.SPSite.OpenWeb() method
- Microsoft.SharePoint.SPSite.AllWebs indexer
- Microsoft.SharePoint.SPSite.RootWeb, LockIssue, Owner, and SecondaryContact properties
- Microsoft.SharePoint.SPSite.AllWebs.Add() method
- Microsoft.SharePoint.SPWeb.GetLimitedWebPartManager() method
- Microsoft.SharePoint.SPWeb.ParentWeb property
- Microsoft.SharePoint.SPWeb.Webs property
- Microsoft.SharePoint.SPWeb.Webs.Add() method
- Microsoft.SharePoint.SPWebCollection.Add() method
- Microsoft.SharePoint.WebControls.SPControl GetContextSite() and GetContextWeb() methods
- Microsoft.SharePoint.SPContext Current.Site / SPContext.Site and SPContext.Current.Web / SPContext.Web properties
- Microsoft.SharePoint.Administration.SPSiteCollection indexer
- Microsoft.SharePoint.Administration.Add() method
- MOSS 2007
SPSite and SPWeb classes both implement the IDisposable interface. Microsoft .NET requires objects that implement the IDisposable interface to properly cleanup the unmanaged resources by explicitly calling the Dispose() method when you are finished using them. Internally, SPSite and SPWeb both hold references to an "internal class Microsoft.SharePoint.Library.SPRequest" which holds on to unmanaged COM resources. The consequence of not explicitly disposing unmanaged resources in a timely fashion can lead to not having enough memory for further allocations and quickly consumes memory. Under the hood, when reviewing dump files we see the that the managed objects used by SPSite and SPWeb are relatively small and it's the unmanaged resources that are most concerning and account for approximately 1MB to 2MB for each object instance! Omitting to explicitly call Dispose() means the .NET (non-deterministic) garbage collector gets out of sync with the finalizer and the unmanaged memory does not get reclaimed in a timely manner possibly blocking future memory allocations. For further reading I recommend reviewing Stefan Goßner's blog Dealing with Memory Pressure problems in MOSS/WSS .
The unmanaged memory leaks can grow very quickly especially when traversing through frequently called areas like site navigation code and item event receivers. The lack of proper Dispose() hygiene can increase your risk of frequent IIS Application Domain recycles (see Steve Sheppard's blog Overlapped Recycling And SharePoint: Why SharePoint Requires It), Out Of Memory (OOM) exceptions, high memory consumption, and poor performing SharePoint production environments.
To Dispose or not Dispose?! That is the question...
To make matters more confusing for SharePoint developers there are times when SPSite and SPWeb objects should not be disposed and are cleaned up by SharePoint and ASP.NET after page processing is completed. In addition, there are cases when developers indirectly call a property on a object that creates and holds an internal reference to a SPSite or SPWeb object (for example SPSite.ParentWeb property). Understanding the origin and the scope the object was created is paramount when determining whether or not to explicitly call dispose.
When writing customized SharePoint code you need to be aware of the scope and context of each SPSite, SPWeb objects lifetime. When objects are created and destroyed in the same method or iteration scope (foreach or do/while loop) they are the easiest to clean handle. Things become more complex to review when developers create objects in one method and dispose in another. Areas to be aware of are assigning objects to class variables or static/global variables which may hold on to the object reference across method calls. The content in this blog post is a combination of Product Group Guidance along with any edge cases that have been discovered in the field through support incidents.
Try / finally using() Dispose()
Make certain that the objects listed here which need to be properly Disposed by your application code is wrapped within a using(), try/finally, or try/catch/finally block. Failure to do so can lead to unexpected memory leaks as there is no other way to guarantee that your Dispose will be reached in the event of an exception. See my updated guidance here.
Troubleshooting Dispose Related Leaks
Recently the SPDisposeCheck utility was announced by Paul Andrew from the Microsoft SharePoint Product Group which was published 1/29/09 here. This command line utility will help scan your custom MOSS and WSS 3.0 .NET assemblies (MSIL not your original source code) automatically scanning for the guidance listed on this blog post. SPDisposeCheck will produce a summary report calling your attention to areas in your code you that you need to closely examine for possible Dispose() related leaks. After you have completed your initial scan with SPDisposeCheck you should examine the SharePoint ULS logs to help further verify that no Dispose() edge cases will be introduced into your shared development, test, and production environments. Stefan Goßner (Microsoft Support Escalation Engineer) has created guidance on using the ULS logs to Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007 . See also Stefan’s Disposing SPWeb and SPSite objects for additional info. For advanced troubleshooting you can ($) contact Microsoft Support or if you have a Premier Contract you can engage Microsoft Premier Support’s Developer Advisory Services (DAS) or Premier Field Engineering (PFE) resources for advanced troubleshooting, debugging, and proactive advisory services including custom code reviews.
SharePoint Memory Internals
400 Level – (Optional read) It’s very important for the developer of the application code to understand when is the optimal time for code optimization and performance reasons to hold on to and release the proper SharePoint objects in a timely fashion. As SharePoint Application developers you should be familiar with the public SPSite and SPWeb objects but internally to get their work done the real managed object that holds onto the unmanaged heap is SPRequestInternalClass which is internal to a wrapper class SPRequest.
Internally we use a RCW (runtime callable wrapper) which is essentially a finalizable object (there are subtle differences but they don’t really come into play here). If that object is no longer rooted, the finalizer (teardown of the RCW) will release the native memory. However, like normal finalizers the RCW teardown is performed by a single finalizer thread which generally can’t keep up with cleaning these objects if they’re being leaked many times per second.
Not releasing the SharePoint objects in a timely fashion can lead to poor memory hygiene including excessive fragmentation, pinning, and OOM exceptions building very quickly. Problematic code which fails to properly dispose objects in a timely fashion becomes exacerbated especially in x32bit environments with a large number of sites. We encourage all Enterprise SharePoint farms to use x64bit versions of the OS and MOSS to take advantage of the additional addressable memory.
Note resources other than just memory are effected by not properly disposing your object in a timely fashion. For example, SQL Server establishes a 1:1 connection with each SPRequest object and it lives up to the release of the internal SPRequest object (which is used by your SPSite and SPWeb object).
- SPList.BreakRoleInheritance() method no longer requires list.ParentWeb.Dispose() to be executed after calling BreakRoleInheritance() due to the updated ParentWeb guidance (see ParentWeb) later in this blog post.
- RootWeb property no longer requires Dispose() to be called on itself as previously indicated in the Whitepaper Best Practices: Using Disposable Windows SharePoint Services Objects . See my blog post here for more detail. In addition, properties LockIssue, Owner, and SecondaryContact internally used the RootWeb property. Based on the updated Microsoft guidance for RootWeb there is no longer a requirement to explicitly Dispose on any of these properties. Note that the owning SPSite object must be properly Disposed (or not Disposed in the case of SPContext) as described by the rules listed elsewhere in this blog.
- new SPSite() operator - Instantiating SPSite objects with the new operator needs to be disposed.
Avoid the following pattern which collapses SPSite and SPWeb calls. The example returns the SPWeb site object wrapped by a using statement which gets disposed but there is no way to dispose the underlying SPSite object.
- AllWebs Indexer returns SPWeb object that needs to be disposed to avoid aggregation of memory which can lead to memory pressure when running on a site collection with large number of sub sites.
- ParentWeb property no longer requires Dispose() as previously indicated in the Whitepaper Best Practices: Using Disposable Windows SharePoint Services Objects . Note that the owning SPSite object must be properly Disposed (or not Disposed in the case of SPContext) as described by the rules listed elsewhere in this blog.
- GetLimitedWebPartManager() method returns a SPWeb object which needs to be disposed.
- GetContextSite(Context) and GetContextWeb(Context) methods return SPSite and SPWeb objects respectively that DO NOT need a call to Dispose() and will be cleaned up automatically by SharePoint.
- SPContext.Current.Site & SPContext.Site as well as SPContext.Current.Web & SPContext.Web properties return SPSite and SPWeb objects respectively that DO NOT need a call to Dispose() and will be disposed automatically by SharePoint.
- GetPublishingWebs() method returns a PublishingWebCollection that you are required to call Close() on each of the returned PublishingWeb objects inside the loop. Note that when you are only calling GetPublishingWeb(SPWeb) method (not the collection) you should not call Close().
- PublishingWeb.GetVariation() method returns a PublishingWeb object which which needs to be explicitly closed.
- PublishingWebCollection.Add() method requires you to call Close() on the returned PublishingWeb object. For a code sample refer to the MOSS SDK GetPublishingWebs() sample.
- Area.Web property creates a SPWeb object that needs to be Disposed(). Although the Area class is obsolete in MOSS 2007 it is still of concern when migrating legacy code.
Cross Method Dispose Patterns
- The following example demonstrates the common practice of holding onto the SPSite and SPWeb objects across methods in a class. There are times where this design pattern is required however make sure you don't overlook the appropriate time to call dispose when you are finished with the cross method calls. Below is an example of this pattern and shows and example of a leak of both SPSite and SPWeb when the class is torn down.
If you extended SharePoint with custom code you should digest this post carefully to avoid expensive consequences commonly found in production environments. For a more verbose explanation of many of the topics covered in this blog post I suggest you read the MSDN White Papers Best Practices: Using Disposable Windows SharePoint Services Objects and Best Practices: Common Coding Issues When Using the SharePoint Object Model .
Special thanks to my Microsoft colleagues on the SPDisposeCheck Core Development team: Sean Thompson, Greg Varveris, and Paul Andrew
Thanks to the many reviewers and contributors including Stefan Goßner, Steve Sheppard, Lisa Guthrie, Cliff Green, and Rick Caudle.