SPDisposeCheck Missing Memory Leaks?

Checking SharePoint memory leaks I came across this blog entry http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_300 describing different types of coding no-nos that can cause memory leaks. As an exercise I created an assembly with all these samples and ran SPDisposeCheck against the assembly and discovered several of the examples were NOT identified by SPDisposeCheck. I wonder If I could be missing something?
 

The following examples were not identified:

 
 

CreatingSPSiteLeak

AllWebsForEachLeak

AllWebsIndexerLeak

SPLimitedWebPartManagerLeak

WebsLeak

PublishingWebCollectionLeak

GetVariationLeak

PersonalSiteLeak

SPSiteCollectionIndexerLeak

SPSiteCollectionForEachLeak

CrossMethodLeak.MethodB

CrossMethodLeak.MethodC

 
 

 
 

SPDispose output text file:

 
 

Note: This tool may report errors which are not actually memory leaks, otherwise known as false positives.

Further investigation should be done to identify and correct real errors.

It is designed to assist developers in making sure their code adheres to best practices for memory allocation when using SharePoint APIs.

Please see the following for more information:

http://blogs.msdn.com/rogerla/

http://msdn2.microsoft.com/en-us/library/aa973248.aspx

http://msdn2.microsoft.com/en-us/library/bb687949.aspx

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_110

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.OpenWebLeak

Statement: local0 := new Microsoft.SharePoint.SPSite(Microsoft.SharePoint.SPContext.get_Current().{Microsoft.SharePoint.SPContext}get_Web().{Microsoft.SharePoint.SPWeb}get_Url()).{Microsoft.SharePoint.SPSite}OpenWeb()

Notes: Constructor called for Microsoft.SharePoint.SPSite but not assigned. This type should be assigned and subsequently disposed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_110

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_150

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.AllWebsAddLeak

Statement: OP_POP local0.{Microsoft.SharePoint.SPSite}get_AllWebs().{Microsoft.SharePoint.SPWebCollection}Add(“site-relative URL”)

Notes: Call to SPWebCollection.Add without capturing return value which should be disposed or closed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_150

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_150

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.WebsAddLeak(System.String)

Statement: OP_POP local1.{Microsoft.SharePoint.SPWeb}get_Webs().{Microsoft.SharePoint.SPWebCollection}Add(strWebUrl)

Notes: Call to SPWebCollection.Add without capturing return value which should be disposed or closed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_150

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_150

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.SPWebCollectionAddLeak(System.String)

Statement: OP_POP local2.{Microsoft.SharePoint.SPWebCollection}Add(strWebUrl)

Notes: Call to SPWebCollection.Add without capturing return value which should be disposed or closed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_150

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_110

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.SPSiteCollectionAddLeak

Statement: local0 := new Microsoft.SharePoint.SPSite(“http://moss”).{Microsoft.SharePoint.SPSite}get_WebApplication()

Notes: Constructor called for Microsoft.SharePoint.SPSite but not assigned. This type should be assigned and subsequently disposed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_110

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_240

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.SPSiteCollectionAddLeak

Statement: OP_POP local1.{Microsoft.SharePoint.Administration.SPSiteCollection}Add(“sites/myNewSiteCollection”, “DOMAIN\\User”, “roger.lamb@litwareinc.com”)

Notes: Call to SPSiteCollection.Add without capturing return value which should be disposed or closed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_240

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_110

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1.SPSiteCollectionAddNoLeak

Statement: local0 := new Microsoft.SharePoint.SPSite(“http://moss”).{Microsoft.SharePoint.SPSite}get_WebApplication()

Notes: Constructor called for Microsoft.SharePoint.SPSite but not assigned. This type should be assigned and subsequently disposed

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_110

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_110

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1+CrossMethodLeak.MethodA

Statement: this._siteCollection := new Microsoft.SharePoint.SPSite(“http://moss”)

Notes:          Disposable type not disposed: Microsoft.SharePoint.SPSite

***This may be a false positive depending on how the type was created or if it is disposed outside the current scope

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_110

———————————————————-

 
 

 
 

ID: SPDisposeCheckID_120

Module: SPDisposeTest.dll

Method: SPDisposeTest.Class1+CrossMethodLeak.MethodA

Statement: this._web := this._siteCollection.{Microsoft.SharePoint.SPSite}OpenWeb()

Notes:          Disposable type not disposed: Microsoft.SharePoint.SPWeb

***This may be a false positive depending on how the type was created or if it is disposed outside the current scope

More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_120

———————————————————-

 
 

Total Found: 9

 
 

———————————————————-

 
 

Modules Checked: 1

———————————————————-

spdisposetest.dll

———————————————————-

 
 

Modules Ignored: 0

———————————————————-

———————————————————-

 
 

Methods Ignored: 0

———————————————————-

 
 

 
 

 
 

The source code for my test assembly:

 
 

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.SharePoint;

using Microsoft.Office.Server;

using Microsoft.Office.Server.UserProfiles;

using Microsoft.SharePoint.Utilities;

using Microsoft.SharePoint.Publishing;

using Microsoft.SharePoint.Portal.WebControls;

using Microsoft.SharePoint.WebControls;

using Microsoft.SharePoint.WebPartPages;

using Microsoft.SharePoint.Administration;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web;

 
 

 
 

namespace SPDisposeTest

{

public
class
Class1

{

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();

}

}

 
 

void CreatingSPSiteWithAutomaticDisposeNoLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

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

}

 
 

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

}

 
 

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

}

 
 

void SPLimitedWebPartManagerLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

SPFile page = web.GetFile(“Source_Folder_Name/Source_Page”);

SPLimitedWebPartManager webPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared);

// SPWeb object webPartManager.Web leaked

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void SPLimitedWebPartManagerNoLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

SPFile page = web.GetFile(“Source_Folder_Name/Source_Page”);

using (SPLimitedWebPartManager webPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared))

{

try

{

// …

}

finally

{

webPartManager.Web.Dispose();

}

}

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void WebsLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb outerWeb = siteCollection.OpenWeb())

{

foreach (SPWeb innerWeb in outerWeb.Webs)

{

// SPWeb innerWeb leak

}

} // SPWeb object outerWeb.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void WebsNoLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb outerWeb = siteCollection.OpenWeb())

{

foreach (SPWeb innerWeb in outerWeb.Webs)

{

try
//should be 1st statement after foreach

{

// …

}

finally

{

if (innerWeb != null)

innerWeb.Dispose();

}

}

} // SPWeb object outerWeb.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void WebsAddLeak(string strWebUrl)

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

SPWeb addedWeb = web.Webs.Add(strWebUrl); // will leak

 
 

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void WebsAddNoLeak(string strWebUrl)

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

using (SPWeb addedWeb = web.Webs.Add(strWebUrl))

{

//..

}

 
 

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void SPWebCollectionAddLeak(string strWebUrl)

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb outerWeb = siteCollection.OpenWeb())

{

SPWebCollection webCollection = siteCollection.AllWebs; // no AllWebs leak just getting reference

SPWeb innerWeb = webCollection.Add(strWebUrl); // must dispose of innerWeb

// innerWeb Leak

} // SPWeb object outerWeb.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void SPWebCollectionAddNoLeak(string strWebUrl)

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb outerWeb = siteCollection.OpenWeb())

{

SPWebCollection webCollection = siteCollection.AllWebs; // no AllWebs leak just getting reference

using (SPWeb innerWeb = webCollection.Add(strWebUrl))

{

//…

}

} // SPWeb object outerWeb.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void SPControlBADPractice()

{

HttpContext Context = null;

SPSite siteCollection = SPControl.GetContextSite(Context);

siteCollection.Dispose(); // DO NOT DO THIS

SPWeb web = SPControl.GetContextWeb(Context);

web.Dispose(); // DO NOT DO THIS

}

 
 

void SPControlBestPractice()

{

HttpContext Context = null;

SPSite siteCollection = SPControl.GetContextSite(Context);

SPWeb web = SPControl.GetContextWeb(Context);

// Do NOT call Dispose()

}

 
 

void SPContextBADPractice()

{

SPSite siteCollection = SPContext.Current.Site;

siteCollection.Dispose(); // DO NOT DO THIS

SPWeb web = SPContext.Current.Web;

web.Dispose(); // DO NOT DO THIS

}

 
 

void SPContextBestPractice()

{

SPSite siteCollection = SPContext.Current.Site;

SPWeb web = SPContext.Current.Web;

// Do NOT call Dispose()

}

 
 

void PublishingWebCollectionLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

// passing in web you own, no dispose needed on outerPubWeb

PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);

 
 

PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();

foreach (PublishingWeb innerPubWeb in pubWebCollection)

{

// innerPubWeb leak

}

// PublishingWeb will leak for each innerPubWeb referenced

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void PublishingWebCollectionNoLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

// passing in web you own, no dispose needed on outerPubWeb

PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);

PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();

foreach (PublishingWeb innerPubWeb in pubWebCollection)

{

try

{

// …

}

finally

{

if (innerPubWeb != null)

innerPubWeb.Close();

}

}

// outerPubWeb.Close(); not needed and if called will log warning in ULS log

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void GetPublishingWebNoLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

// passing in web you own, no dispose needed on singlePubWeb

PublishingWeb singlePubWeb = PublishingWeb.GetPublishingWeb(web);

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void GetVariationLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in web so no Close() needed

VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];

PublishingWeb variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // must be Closed()

// …

} // SPWeb object web.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void GetVariationNoLeak()

{

using (SPSite siteCollection = new SPSite(http://moss))

{

using (SPWeb web = siteCollection.OpenWeb())

{

PublishingWeb variationPublishingWeb = null;

try

{

PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in web so no Close() needed

VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];

variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // must be Closed()

// …

}

finally

{

if (variationPublishingWeb != null)

variationPublishingWeb.Close();

}

} // SPWeb object outerWeb.Dispose() automatically called

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

void PersonalSiteLeak()

{

// open a site collection

using (SPSite siteCollection = new SPSite(http://moss))

{

UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));

UserProfile profile = profileManager.GetUserProfile(“domain\\username”);

SPSite personalSite = profile.PersonalSite; // will leak

}

}

 
 

void PersonalSiteNoLeak()

{

// open a site collection

using (SPSite siteCollection = new SPSite(http://moss))

{

UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));

UserProfile profile = profileManager.GetUserProfile(“domain\\username”);

using (SPSite personalSite = profile.PersonalSite)

{

// …

}

}

}

 
 

void SPSiteCollectionIndexerLeak()

{

using (SPSite siteCollectionOuter = new SPSite(http://moss))

{

SPWebApplication webApp = siteCollectionOuter.WebApplication;

SPSiteCollection siteCollections = webApp.Sites;

 
 

SPSite siteCollectionInner = siteCollections[0];

// SPSite siteCollectionInner leak

} // SPSite object siteCollectionOuter.Dispose() automatically called

}

 
 

void SPSiteCollectionIndexerNoLeak()

{

using (SPSite siteCollectionOuter = new SPSite(http://moss))

{

SPSite siteCollectionInner = null;

try

{

SPWebApplication webApp = siteCollectionOuter.WebApplication;

SPSiteCollection siteCollections = webApp.Sites;

 
 

siteCollectionInner = siteCollections[0];

}

finally

{

if (siteCollectionInner != null)

siteCollectionInner.Dispose();

}

} // SPSite object siteCollectionOuter.Dispose() automatically called

}

 
 

void SPSiteCollectionForEachLeak()

{

using (SPSite siteCollectionOuter = new SPSite(http://moss))

{

SPWebApplication webApp = siteCollectionOuter.WebApplication;

SPSiteCollection siteCollections = webApp.Sites;

 
 

foreach (SPSite siteCollectionInner in siteCollections)

{

// SPSite siteCollectionInner leak

}

} // SPSite object siteCollectionOuter.Dispose() automatically called

}

 
 

void SPSiteCollectionForEachNoLeak()

{

using (SPSite siteCollectionOuter = new SPSite(http://moss))

{

SPWebApplication webApp = siteCollectionOuter.WebApplication;

SPSiteCollection siteCollections = webApp.Sites;

 
 

foreach (SPSite siteCollectionInner in siteCollections)

{

try

{

// …

}

finally

{

if (siteCollectionInner != null)

siteCollectionInner.Dispose();

}

}

} // SPSite object siteCollectionOuter.Dispose() automatically called

}

 
 

void SPSiteCollectionAddLeak()

{

SPWebApplication webApp = new SPSite(http://moss”).WebApplication;

SPSiteCollection siteCollections = webApp.Sites;

SPSite siteCollection = siteCollections.Add(“sites/myNewSiteCollection”, “DOMAIN\\User”, “roger.lamb@litwareinc.com”);

// SPSite siteCollection leak

}

 
 

void SPSiteCollectionAddNoLeak()

{

SPWebApplication webApp = new SPSite(http://moss”).WebApplication;

SPSiteCollection siteCollections = webApp.Sites;

using (SPSite siteCollection = siteCollections.Add(“sites/myNewSiteCollection”, “DOMAIN\\User”, “roger.lamb@litwareinc.com”))

{

} // SPSite object siteCollection.Dispose() automatically called

}

 
 

public
class
CrossMethodLeak

{

private SPSite _siteCollection = null;

private SPWeb _web = null;

 
 

public
void MethodA()

{

_siteCollection = new SPSite(http://moss);

_web = _siteCollection.OpenWeb();

}

 
 

public
void MethodB()

{

if (_web != null)

{

string title = _web.Title;

}

}

 
 

public
void MethodC()

{

if (_web != null)

{

string name = _web.Name;

}

}

}

}

}

 
 

 UPDATE:  Mystery Solved! – https://stephenvick.wordpress.com/2009/03/20/mystery-solved-spdisposecheck-missing-memory-leaks/

Advertisements

4 Responses to “SPDisposeCheck Missing Memory Leaks?”

  1. Matt Ranlett Says:

    I sent a pointer to this blog post on to the MVP mailing list to attempt to catch the attention of the SharePoint product team.

  2. Paul Andrew Says:

    Hi Stephen,

    Matt forwarded me a link to this. I’m on the SPDisposeCheck team at Microsoft. We are planning a new release of the tool which should correct the behavior that you have seen. In the mean time, you can get it to report all of the issues by building your code as Debug instead of Release. Your Release build seems to have optimized away some of the things we use to check for leaks. We’ll fix it so that we see those also in the next release.

    Regards,
    Paul

  3. ÁghyBlog » links for 2009-03-21 Says:

    […] SPDisposeCheck Missing Memory Leaks? (tags: sharepoint2007 development SPDisposeCheck) […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: