- 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, andSecondaryContact 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.
Note: With C# you can automatically have the Dispose() called for you when the object leaves the scope by wrapping the code with the using() { } statement.
void CreatingSPSiteLeak() { SPSite siteCollection = new SPSite("http://moss"); // siteCollection leaked } void CreatingSPSiteExplicitDisposeNoLeak() { SPSite siteCollection = null; try { siteCollection = new SPSite("http://moss"); } finally { if (siteCollection != null) siteCollection.Dispose(); } } CreatingSPSiteWithAutomaticDisposeNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { } // SPSite object siteCollection.Dispose() automatically called }
Avoid the following pattern which collapses SPSite and SPWeb calls. The example returns theSPWeb site object wrapped by a using statement which gets disposed but there is no way to dispose the underlying SPSite object.
void OpenWebLeak() { using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb()) { // SPSite leaked ! } // SPWeb object web.Dispose() automatically called } void OpenWebNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb web = siteCollection.OpenWeb()) { } // SPWeb object web.Dispose() automatically called } // SPSite object siteCollection.Dispose() automatically called }
- 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.
void AllWebsForEachLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb outerWeb = siteCollection.OpenWeb()) { foreach (SPWeb innerWeb in siteCollection.AllWebs) { // explicit dispose here to avoid OOM's with large # of webs } } // SPWeb object outerWeb.Dispose() automatically called } // SPSite object siteCollection.Dispose() automatically called } void AllWebsForEachNoLeakOrMemoryOOM() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb outerWeb = siteCollection.OpenWeb()) { foreach (SPWeb innerWeb in siteCollection.AllWebs) { try { // ... } finally { if(innerWeb != null) innerWeb.Dispose(); } } } // SPWeb object outerWeb.Dispose() automatically called } // SPSite object siteCollection.Dispose() automatically called } void AllWebsIndexerLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { SPWeb web = siteCollection.AllWebs[0]; // SPWeb web leaked } // SPSite object siteCollection.Dispose() automatically called } void AllWebsIndexerNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb web = siteCollection.AllWebs[0]) { } // SPWeb object web.Dispose() automatically called } // SPSite object siteCollection.Dispose() automatically called }
- AllWebs.Add() returns a instance of SPWeb object which needs to be disposed.
void AllWebsAddLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { SPWeb web = siteCollection.AllWebs.Add("site-relative URL"); // SPWeb web Leaked } // SPSite object siteCollection.Dispose() automatically called } void AllWebsAddNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb web = siteCollection.AllWebs.Add("site-relative URL")) { } // SPWeb object web.Dispose() automatically called } // SPSite object siteCollection.Dispose() automatically called }
No comments:
Post a Comment