Stefan Goßner

Senior Escalation Engineer for SharePoint (WSS, SPS, MOSS, SP2010) and MCMS

Disposing SPWeb and SPSite objects

Disposing SPWeb and SPSite objects

  • Comments 25
  • Likes

There are several articles around discussing the dispose of SPWeb and SPSite objects, e.g.:

And also in a couple of articles I wrote myself:

So we all should know how important it is to actually dispose all SPSite and SPWeb objects we create in our code to avoid problems.

Today I would like to highlight some additional aspects which might not be that obvious.
 

1) What happens if a SPWeb object is not disposed?

As discussed in my earlier article each SPWeb and SPSite object holds a reference to an 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 (see the MaxUserPort registry setting for details). 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.
 

2) Does this mean that the allocated space will remain in memory forever if the SPWeb/SPSite object is not disposed?

With WSS 2.0 (and SPS 2003 as it sits on top of WSS 2.0) the answer would be yes - at least under heavy load. Only an application pool recycle would allow to recover from such a situation. The reason for this is that under heavy load the finalizer will not execute in a timely fashion and the server can quickly get into a memory pressure situation, so a proper disposal is important.

With WSS 3.0 (and MOSS 2007 as it sits on top of WSS 3.0) the answer is actually no. There are two different mechanisms to mitigate the impact of custom code that does not properly dispose SPSite and SPWeb objects.

Method 1: SPWeb tracking by SPSite

Whenever an SPWeb object is created the SPSite object associated with the new SPWeb object automatically adds the new SPWeb object to an internal list. This works for all SPWeb object creations - be it through SPWeb.OpenWeb, SPSite.RootWeb, SPWeb.ParentWeb or any other method that directly or indirectly creates an SPWeb object.

When the SPSite object finally gets disposed it will loop through the list and ensure that all SPWeb objects associated with this SPSite object also get disposed.

This might lead to the assumption that just disposing all SPSite objects rather than disposing each individual SPWeb object would be sufficient to minimize the memory usage. In theory this is correct. But it will postpone the dispose of the SPWeb object to the time when the SPSite object gets disposed. So the dispose does not happen right after the SPWeb object is no longer used but much later.

Especially when you have a loop like the following an explicit dispose of the SPWeb object is mandatory to minimize the number of undisposed SPWeb objects in the process:

foreach (SPWeb web in site.AllWebs) 

     
// do something with the web object 
    web.dispose();        
// <-- this is mandatory!
}

Method 2: SPRequest tracking

The previous Method is the savety net for code that misses to dispose SPWeb object. But it does not protect against missing SPSite object disposal. To protect against missing SPSite object disposal WSS 3.0 tracks each created SPRequest object and keeps it in a list together with the information on which thread it was created till the creating object gets disposed. Whenever a thread finishes WSS verfies if there are any SPRequest objects in it's list. If it finds any it ensures that the COM object bound ot this SPRequest object closes the connection to the SQL server and that the memory allocated by the COM component is released.

In addition it writes the an entry into the ULS log of the following type:

05/01/2007 12:58:47.31                w3wp.exe (0x105C)                                      0x09A8 Windows SharePoint Services                   General                               8l1n       High       An SPRequest object was not disposed before the end of this thread...
(see the following article to get more details about this message)

Be aware that threads are often reused for multiple requests. That means that a missing dispose for a SPSite object will cause the resources allocated by the COM component to remain much longer in memory as if a dispose for a SPWeb object was missing where the SPSite object was properly disposed.

As we can see in WSS 3.0 additional mechanisms have been added to ensure that incorrectly coded components don't have the same impact on the availability of the system as in WSS 2.0. These mechanisms help to fix issues where single objects have not been disposed. But if code that misses to dispose SPWeb or SPSite objects get called in a repeated manner it can still lead to high memory consumption up to out of memory problems.
 

3) When should SPWeb and SPSite objects be disposed?

The answer for this is: as soon as it is no longer needed. That sounds simple - but sometimes this is not easy to determine.

Ok, for code like the following the answer is simple:

foreach (SPWeb web in site.AllWebs) 

     
// do something with the web object 
    web.dispose();        
// <-- this is mandatory!
}

Here the dispose needs to be the last statement of the loop.

But what if you have code like the following:

SPSite site = new SPSite();
SPWeb web = site.RootWeb;
// Position 1

SPList list = web.Lists["MyList"]

// Position 2

...code that uses the list object...

// Position 3

Where should you add the dispose for the SPSite and SPWeb object? When are the objects no longer used?

Ok, if you have read the previous paragraph you will notice that a dispose for the SPSite object in position 1 will automatically dispose all SPWeb objects bound to the SPSite object. So it will dispose the SPWeb object used after Position 1 to access the list. So that would mean Position 1 is not the right place.

What about Position 2? Can we dispose the SPSite object here? Or at least SPWeb object? The code does not show a usage of any of these objects. So a dispose seems to be save, right?

Actually some internal methods of the SPList object access the SPWeb object it belongs to to perform certain operations. So we cannot dispose the SPWeb object here without side effects. And that also means that we cannot dispose the SPSite object here as it would automatically dispose the SPWeb objects.

That means that we have to dispose the SPWeb and SPSite object at Position 3 and not earlier.

What would happen if we would add code to dispose the SPWeb or SPSite object earlier? In some rare cases you will see an exception. But in most cases you would not see a problem with your code! Everything would work fine - but why?

The reason is that many methods silently recreate the SPWeb objects if it has been disposed. That means: even though you disposed the object in your code - a couple of code lines later it suddenly reappears and would have to be disposed again.

So the answer to the question is: 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.
 

4) 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.
 

5) Can I cache SharePoint objects in session variables?

That question is a little bit off topic but as it is related to the underlaying SPRequest objects I decided to cover it here.

As we discussed in 2) WSS 3.0 monitors the thread termination and releases all SPRequest objects allocated on during the livetime of this specific thread. When storing SharePoint objects in session variables then the objects will usually be accessed on different threads - which is not allowed. One of the reasons is that the COM resources for the objects will get released when the thread that created the objects terminates - independent if other threads still use it.

What you can do is to store the meta information of SharePoint objects (like the URL, the GUID, ...) in session variables. But not the SharePoint objects themselves.
 

6) Is it also important to dispose SPWeb objects on 64-bit machines with lots of memory?

Even on a 64-bit machine you have the same limitation regarding user ports (see paragraph 1). It is possible to increase the number of user ports in the registry but there is still a maximum size which could be reached with large sites or multiple application pools if the code does not properly handle dispose of SPWeb objects.  
 

7) 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.

You need to ensure that you only dispose SPSite and SPWeb objects that your code owns.

[Update Dec 7th, 2008] Please also have a look at the following article which is actually a response to this article and has many additional samples for the things I mentioned here.

Comments
  • <p>PingBack from <a rel="nofollow" target="_new" href="http://solutionizing.net/2008/12/06/the-new-definitive-spsitespweb-disposal-article/">http://solutionizing.net/2008/12/06/the-new-definitive-spsitespweb-disposal-article/</a></p>

  • <p>Thanks for this, be great to get this up on the new <a rel="nofollow" target="_new" href="http://www.sharepointdevwiki.com/">http://www.sharepointdevwiki.com/</a> Let me know if you’re happy to submit it. That way people can evolve it in a wiki rather than an updated blog post etc. Be interested to hear your thoughts on it Stefan.</p>

  • <p>excellent write up mate, thanks!</p>

  • <p>Great Post!</p> <p>I have one question</p> <p>I guess it's ok to dispose in the following situation?</p> <p>public override void ItemCheckingOut(SPItemEventProperties properties)</p> <p>{</p> <p> &nbsp; SPWeb web = properties.OpenWeb()</p> <p> &nbsp; //Do stuff...</p> <p> &nbsp; web.dispose();</p> <p>}</p> <p>Cheers, </p> <p>Rick</p>

  • <p>Hi Rick,</p> <p>yes this call will construct a new SPWeb object which you actually have to dispose.</p> <p>Cheers,</p> <p>Stefan</p>

  • <p>Stefan ~</p> <p>Looking at the internals behind the various EventProperties, I'm not finding anywhere that the framework actually cleans up disposable objects allocated to create the child items. SPItemEventProperties is even IDisposable, but Dispose() is never called that I can find.</p> <p>Since the SP* objects returned aren't even created until the property is referenced, it seems to me the best practice here would be to create your own SPSite/SPWeb and clean it up yourself. What do you think?</p> <p>If this is the case, it's also worth mentioning that SPItemEventProperties.OpenWeb() will internally allocate an SPSite that needs to be cleaned up by the caller.</p> <p>Cheers ~</p> <p>Keith</p>

  • <p>Hi Keith,</p> <p>actually there are two different constructors for SPItemEventProperties.</p> <p>One of them passes a SPSite object into the constructor which is then set as the relevant SPSite member variable.</p> <p>As the event receiver cannot control how the SPItemEventProperties object has been created it is not allowed to dispose this object as this object might be the SPSite object coming from SPContext (e.g.).</p> <p>Regarding IDisposable of SPItemEventProperties: you are right. I just double checked. This looks like a problem in our code. I will forward this info to the right people here.</p> <p>Cheers,</p> <p>Stefan</p>

  • <p>I agree that it isn't the SPItemEventProperties object's responsibility to dispose of an SPSite that was passed in, which is handled nicely by the logic within Dispose(). Whether or not Dispose() is called is its creator's problem. However, that contract does not exist for SPListEventProperties and SPWebEventProperties, which leads me to believe the auxiliary sites and webs are allowed to leak.</p> <p>I'm inclined to mimic the built-in receivers, almost all of which create their own SPSite/SPWeb as necessary and Dispose() when they're done.</p> <p>Regards ~</p> <p>Keith</p>

  • <p>Hi Keith,</p> <p>intersting. I will check into this in more detail tomorrow and post my results.</p> <p>Cheers,</p> <p>Stefan</p>

  • <p>Linki, kt&#243;re posłużyły mi przy tworzeniu prezentacji, z kt&#243;rych czerpałem wiedzę, nakładałem ją na to</p>

  • <p>Un a&#241;o m&#225;s ( &#161;FELIZ A&#209;O NUEVO A TODOS! ), aqu&#237; estoy dando guerra (y ya van m&#225;s de dos desde que Rodrigo</p>

  • <p>Hey Stefan ~</p> <p>I've posted a revision of my disposal article on the SharePoint Dev Wiki here:</p> <p><a rel="nofollow" target="_new" href="http://sharepointdevwiki.com/display/public/When+to+Dispose+SharePoint+objects">http://sharepointdevwiki.com/display/public/When+to+Dispose+SharePoint+objects</a></p> <p>I'd appreciate if you could look it over for anything incorrect or omitted.</p> <p>Thanks ~</p> <p>Keith</p>

  • <p>Chances are that by now if you have been developing on the Microsoft SharePoint Office Server (MOSS)</p>

  • <p>This is a very nice blog on WSS object disposal and preventing bad memory usage. But What about those web parts that are created using Sharepoint Designer that uses XSLT to render the web part? Do they handle the disposal of SPSite and SPWeb objects internally? </p>

  • <p>SPSite and SPWeb implement the IDisposable interface</p>

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment