How to spot the problem? |
|
1st Approach |
If your sites are displaying any of the unusual behaviors described previously, you can determine whether the cause is a memory leak due to incorrectly disposed objects by checking the ULS logs (available at C:\Program Files\Common Files\microsoft shared\Web Server Extensions\12\LOGS) for entries related to the SPRequest object.Each instance of SPSite and SPWeb contains a reference to an SPRequest object that,in turn, contains a reference to an unmanaged COM object that handles communications with the database server. Windows SharePoint Services monitors the number of SPRequest objects that exist in each specific thread and in parallel threads, and adds useful entries to the logs. For more information on this click here: |
2nd Approach: |
Microsoft provides a tool to help you detect and track down objects you aren’t disposing of properly called the SharePoint Dispose Checker tool. That tool is found here: http://code.msdn.microsoft.com/SPDisposeCheck |
Coding Techniques to Ensure Object Disposal |
You can employ certain coding techniques to ensure object disposal. These techniques include using the following in your code:
|
Dispose method |
The basic idea behind using the Dispose method is you call it on an IDisposable object when you are done with it. At the point you call Dispose on the object the managed and unmanaged memory associated with the object is reclaimed. The object is also no longer usable after you call Dispose on it—any subsequent calls to the object will result in an error. Example SPSite mySite = new SPSite("http://mySite"); //do something with mysite mySite.Dispose(); //disposes of memory used by mysite //now don’t use mySite object as it will throw error |
The using Clause |
You can automatically dispose of SharePoint objects that implement the IDisposable interface by using the Microsoft Visual C# using statement. Example String str;
using(SPSite oSPsite = new SPSite("http://Myserver"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
}
}
It also makes your code more clear and makes it impossible for you to accidentally call into the object after it has been disposed because it also goes out of scope when you are done with it. |
The try, catch, and finally Blocks |
Using try, catch, and finally blocks obviously makes sense whenever you need to handle exceptions. Any code within a try/catch block should have a governing finally clause, which ensures that the objects that implement IDisposable are disposed. There are cases in your code where you may be creating objects that are IDisposable that may not be as obvious. For example, you may have a foreach loop that iterates over a collection that returns SPSite or SPWeb objects. For these cases you use a try, finally block in the iterator to ensure that each IDisposable object created in the foreach loop is disposed of properly. Example using (SPSite spSite = new SPSite('http://mysite/')) { foreach (SPWeb spweb in spSite.AllWebs) { try { Console.WriteLine(spweb.Name); } finally { if (spweb != null) { spweb.Dispose(); } } } }
Whenever you
wish to free memory resources, call Dispose method, instead of the Close method
, internally Dispose method calls Close method itself, the reason being that
standard .NET Framework process calls the Dispose method to free memory
resources associated with object.
Thankfully
Microsoft has recently launched Sharepoint Dispose Checker utility. It will
ensure that you have properly disposed objects so that you aren’t consuming
more memory. All developers should run this utility after they use Sharepoint
object model. Click here to download
SPDispose Utility.
Best
Practice #1: Use the Using Clause for all Sharepoint objects that implement the
IDisposable interface
C# Coding
snippet
String str;
using(SPSite
oSPsite = new SPSite("http://server"))
{
using(SPWeb
oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
}
}
Best
Practice #2: Use the try/catch/finally blocks. When you use try blocks, it is important
to add a finally block to ensure that all objects are disposed off properly:
C# Coding
snippet
String str;
SPSite oSPSite
= null;
SPWeb oSPWeb =
null;
try
{
oSPSite = new
SPSite("http://server");
oSPWeb =
oSPSite.OpenWeb(..);
str =
oSPWeb.Title;
}
catch(Exception
e)
{
}
finally
{
if (oSPWeb !=
null)
oSPWeb.Dispose();
if (oSPSite !=
null)
oSPSite.Dispose();
}
Best
Practice #3: Using Response.Redirect in the try block will never execute the finally
block, so it is important, to dispose off all objects before the redirection
occurs:
C# Coding
snippet
String str;
SPSite oSPSite
= null;
SPWeb oSPWeb =
null;
bool
bDoRedirection = true;
try
{
oSPSite = new
SPSite("http://server");
oSPWeb =
oSPSite.OpenWeb(..);
str =
oSPWeb.Title;
if(bDoRedirection)
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
Response.Redirect("newpage.aspx");
}
}
catch(Exception
e)
{
}
finally
{
if (oSPWeb !=
null)
oSPWeb.Dispose();
if (oSPSite !=
null)
oSPSite.Dispose();
}
Best
Practice #4: Whenever you create an object with a new operation, the creating
application must dispose it off
C# Coding
snippet
SPSite oSPSite
= new SPSite("http://server");
... additional
processing on SPSite ...
oSPSite.Dispose();
alternatively,
this is a better approach
C# Coding
snippet
using(SPSite
oSPSite = new SPSite("http://server"))
{
... additional
processing on SPSite ...
}
Best
Practice #5: For Site.OpenWeb method, you need to dispose it off explicitly.
C# Coding
snippet
String str;
SPSite oSPSite
= new SPSite("http://server");
SPWeb oSPWeb =
oSPSite.OpenWeb();
str =
oSPWeb.Title;
str =
oSPWeb.Url;
... additional
processing on SPWeb ...
oSPWeb.Dispose();
oSPSite.Dispose();
Alternatively
you may use the Using clause too for better readability and automatic
disposition of objects:
C# Coding
snippet
String str;
using(SPSite
oSPSite = new SPSite("http://server"))
{
using(SPWeb
oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
... additional processing on SPWeb ...
}
}
Best
Practice #6: An exception to the rule is that One should not explicitly dispose
SPSite.RootWeb, as it is automatically disposed off.
Similary one
should not explicity dispose SPContext.Current.Site and SPContext.Current.Web
as they are handles automatically by Sharepoint and .NET framework.
C# Bad Coding
Practice Snippet:
void
SPContextBADPractice()
{
SPSite siteCollection =
SPContext.Current.Site;
siteCollection.Dispose(); // DO NOT DO THIS
SPWeb web = SPContext.Current.Web;
web.Dispose(); // DO NOT DO THIS
}
C# Good Coding
Practice Snippet:
void
SPContextBestPractice()
{
SPSite siteCollection =
SPContext.Current.Site;
SPWeb web = SPContext.Current.Web;
// Do NOT call Dispose()
}
Best
Practice #7: SPControl.GetContextSite(Context) and GetContextWeb(Context) return SPSite
and SPWeb respectively, they do not need an explicit call to Dispose(), they
will be disposed automatically
C# Bad Coding
Practice Snippet:
void
SPControlBADPractice()
{
SPSite siteCollection =
SPControl.GetContextSite(Context);
siteCollection.Dispose(); // DO NOT DO THIS
SPWeb web = SPControl.GetContextWeb(Context);
web.Dispose();
// DO NOT DO THIS
}
C# Good Coding
Practice Snippet:
void
SPControlBestPractice()
{
SPSite siteCollection =
SPControl.GetContextSite(Context);
SPWeb web = SPControl.GetContextWeb(Context);
// Do NOT call Dispose()
}
Best
Practice #8: SPWeb.ParentWeb returns SPWeb, and
needs to be disposed off explicitly using either Dispose() or the using clause
C# Bad Coding
Practice Snippet:
void
ParentWebLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb =
siteCollection.OpenWeb())
{
SPWeb parentWeb = outerWeb.ParentWeb;
// Internal reference to SPWeb parentWeb
string sTitle = parentWeb.Title;
string sUrl = parentWeb.Url;
// SPWeb object parentWeb leaked
} // SPWeb object outerWeb.Dispose()
automatically called
} //
SPSite object siteCollection.Dispose() automatically called
}
C# Good Coding
Practice Snippet:
void
ParentWebBestPractice()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
using (SPWeb outerWeb =
siteCollection.OpenWeb())
{
using (SPWeb parentWeb =
outerWeb.ParentWeb) // Internal reference to SPWeb parentWeb
{
string sTitle = parentWeb.Title;
string sUrl = parentWeb.Url;
} // SPWeb object parentWeb.Dispose()
automatically called
} // SPWeb object outerWeb.Dispose()
automatically called
} //
SPSite object siteCollection.Dispose() automatically called
}
Best
Practice #9: SPWeb.Webs returns an SPWeb object, practically used in drilling down
sub-sites within a Site
C# Bad Coding
Practice Snippet:
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
}
C# Good Coding
Practice Snippet:
void
WebsBestPractice()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
using (SPWeb outerWeb =
siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in
outerWeb.Webs)
{
innerWeb.Dispose();
}
} // SPWeb object outerWeb.Dispose()
automatically called
} //
SPSite object siteCollection.Dispose() automatically called
}
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. Practically used in Enumerating or iterating all webs in a site
collection.
C# Bad Coding
Practice Snippet:
void
AllWebsForEachLeakBestPractices()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
using (SPWeb outerWeb =
siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in
siteCollection.AllWebs)
{
// Explicit Dispose must be called to avoid
aggregation of memory
}
} // SPWeb object outerWeb.Dispose()
automatically called
} //
SPSite object siteCollection.Dispose() automatically called
}
C# Good Coding
Practice Snippet:
void AllWebsForEachLeakBestPractices()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
using (SPWeb outerWeb =
siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in
siteCollection.AllWebs)
{
innerWeb.Dispose(); // Explicit Dispose must be called to avoid
aggregation of memory
}
} // SPWeb object outerWeb.Dispose()
automatically called
} //
SPSite object siteCollection.Dispose() automatically called
}
C# Bad Coding
Practice Snippet:
void
AllWebsIndexerLeak()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
SPWeb web = siteCollection.AllWebs[0];
// SPWeb web leaked
} //
SPSite object siteCollection.Dispose() automatically called
}
C# Good Coding
Practice Snippet:
void
AllWebsIndexerBestPractice()
{
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
}
C# Bad Coding
Practice Snippet:
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
}
C# Good Coding
Practice Snippet:
void
AllWebsAddBestPractice()
{
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
}
C# Bad Coding
Practice Snippet:
void
OpenWebLeak()
{
using (SPWeb web = new
SPSite(SPContext.Current.Web.Url).OpenWeb())
{
// SPSite leaked !
} // SPWeb object web.Dispose() automatically
called
}
C# Good Coding
Practice Snippet:
void
OpenWebBestPractice()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
using (SPWeb web =
siteCollection.OpenWeb())
{
} // SPWeb object web.Dispose()
automatically called
} //
SPSite object siteCollection.Dispose() automatically called
}
Best
Practice #13:new SPSite() -
Instantiating SPSite objects with
the new operator needs to be disposed.
C# Bad Coding
Practice Snippet:
void
CreatingSPSiteLeak()
{
SPSite siteCollection = new
SPSite("http://moss");
// siteCollection leaked
}
C# Good Coding
Practice Snippet:
void
CreatingSPSiteExplicitDisposeBestPractice()
{
SPSite siteCollection = new
SPSite("http://moss");
siteCollection.Dispose();
}
void
CreatingSPSiteWithAutomaticDisposeBestPractice()
{
using (SPSite siteCollection = new
SPSite("http://moss"))
{
} // SPSite object siteCollection.Dispose()
automatically called
}
|
Thursday, March 7, 2013
Recommended Practices for disposing objects in SharePoint Development
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment