Wednesday, March 11, 2009

Disposing SPWeb and SPSite objects

What happens if a SPWeb object is not disposed?

Each SPWeb and SPSite object holds a reference to a SPRequest object which holds a reference to a SharePoint COM object that is responsible to communicate with the backend SQL server.

Disposing a SPWeb object will not actually remove the SPWeb object from memory (actually the .NET framework does not allow to remove any object from memory in a deterministic way) but it will call a method of the SPWeb object which causes the COM object to close the connection to the SQL server and to release its allocated memory.

That means the connection to the backend SQL server will remain open from the moment the SPRequest object has been created till the SPWeb object is disposed.
After the dispose only the small managed SPWeb and SPRequest objects remain in memory which do not create a big memory overhead. They are removed by the dot net framework through garbage collection later as with any other managed object as soon as no references to the object exist any more.

In case that the SPWeb object is not disposed when it is no longer used, then the connection to the SQL server will stay open and the memory allocated by the COM object will stay in memory as the COM object has not been asked to close the connection and to release the memory.

Each connection to the database requires a tcp port for the communication. Per default only 5000-1023 = 3977 ports are available. Which means on a single machine per default you cannot have more than 3977 open connections to other applications. Be aware that this is the number for all processes. Not just a single application pool.

So beside the fact that not disposing SPWeb and SPSite will lead to a higher memory consumption which finally can lead to out of memory exceptions the machine might also run out of TCP ports which would lead to lots of other problems - potentially also in other applications on the same server.

When should SPWeb and SPSite objects be disposed?

You should dispose a SPWeb or SPSite object after the last access to a child object of this object. Be aware that a sub site (SPWeb) is not a child object. But (e.g.) a list or a folder or list item is a child object for this scenario.


When should I dispose SPSite.RootWeb?

When SPSite.RootWeb is first accessed it creates an SPWeb object using SPSite.OpenWeb and stores a reference in an internal variable. Further accesses to SPSite.RootWeb are then satisfied by returning a reference to the earlier created object. In case the RootWeb object has been disposed it will create a new one using OpenWeb as for the initial access.

That means we have a single SPWeb object per SPSite object even if we access SPSite.RootWeb multiple times. Creating a SPWeb object is an expensive operation as it requires the instantiation of a COM object, a database communication to download the info about the SPWeb object and so on. That means disposing the RootWeb object after every single access to it can affect the performance of the site - especially if you have many different places in your project that do the same for the same SPSite object. So ensure to dispose the RootWeb object only after the last access to it in your code whereever the logic of the code allows to determine this.
Also please do not dispose the RootWeb property of SPContext.Current.Site. This object is used in many different places in SharePoint and you should not dispose it. It will automatically be cleaned up when the request finishes.

-----------------------------------------------------------------------
Dispose of objects which do not belong to the method?

In general SPSite and SPWeb objects should be disposed in the same method they get allocated. That's the best method to ensure that no disposed can be missed and to ensure that a dispose does not occur for an object that will be used later.
I have seen several cases where custom code disposed SPWeb and SPSite objects incorrectly.

A very common scenario is the following:
...

using (SPSite mySite = SPContext.Current.Site)
{
...
}
...
Using "using" statements is a very nice method to ensure that at the end the object being used gets properly disposed. The problem in the code above is that SPContext.Current.Site and SPContext.Current.Web are not allowed to be disposed! Using successfully hides the dispose statement here. "Using" allows a nice structuring of the code so users often use it without thinking about the side effects.

If you plan to use a using statement with SPContext you need to code it like this:
...
using (SPSite mySite = new SPSite(SPContext.Current.Site.ID))
{
...
}
...
This method will ensure that a new independent SPSite object is created which you then can dispose without side effects on other code using the SPSite object bound to the current SPContext object.
-----------------------------------------------------------------------
Another common error is to dispose an SPSite or SPWeb object in a event receiver:

public override void ItemCheckingOut(SPItemEventProperties properties)
{
...
// incorrect dispose of SPWeb
using (SPWeb web = properties.ListItem.Web)
{
}
...
// incorrect dispose of SPSite
using (SPWeb site = properties.ListItem.Web.Site)
{
}
...
}
After executing our code other event receivers will receive an object where the underlaying SPWeb and/or SPSite object has been disposed. This can lead to exceptions.

-----------------------------------------------------------------------
// Do not do this. Dispose() is automatically called on SPWeb.
using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { ... }
SPContext objects are managed by the SharePoint framework and should not be explicitly disposed in your code. This is true also for the SPSite and SPWeb objects returned by SPContext.Site, SPContext.Current.Site, SPContext.Web, and SPContext.Current.Web.
You must be cautious and aware of what the runtime is doing whenever you combine SharePoint object model calls on the same line. Leaks arising from this scenario are among the hardest to find.

2 comments:

Anonymous said...

Nice copy paste from technet

Anonymous said...

Hope this helps you doing more copy paste

http://blogs.technet.com/b/stefan_gossner/archive/2008/12/05/disposing-spweb-and-spsite-objects.aspx