Disposing SPWeb and SPSite objects

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.

27 Comments


  1. Thanks for this, be great to get this up on the new http://www.sharepointdevwiki.com/ 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.

    Reply

  2. excellent write up mate, thanks!

    Reply

  3. Great Post!

    I have one question

    I guess it’s ok to dispose in the following situation?

    public override void ItemCheckingOut(SPItemEventProperties properties)

    {

      SPWeb web = properties.OpenWeb()

      //Do stuff…

      web.dispose();

    }

    Cheers,

    Rick

    Reply

  4. Hi Rick,

    yes this call will construct a new SPWeb object which you actually have to dispose.

    Cheers,

    Stefan

    Reply

  5. Stefan ~

    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.

    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?

    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.

    Cheers ~

    Keith

    Reply

  6. Hi Keith,

    actually there are two different constructors for SPItemEventProperties.

    One of them passes a SPSite object into the constructor which is then set as the relevant SPSite member variable.

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

    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.

    Cheers,

    Stefan

    Reply

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

    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.

    Regards ~

    Keith

    Reply

  8. Hi Keith,

    intersting. I will check into this in more detail tomorrow and post my results.

    Cheers,

    Stefan

    Reply

  9. Linki, które posłużyły mi przy tworzeniu prezentacji, z których czerpałem wiedzę, nakładałem ją na to

    Reply

  10. Un año más ( ¡FELIZ AÑO NUEVO A TODOS! ), aquí estoy dando guerra (y ya van más de dos desde que Rodrigo

    Reply

  11. Chances are that by now if you have been developing on the Microsoft SharePoint Office Server (MOSS)

    Reply

  12. 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?

    Reply

  13. SPSite and SPWeb implement the IDisposable interface

    Reply

  14. Hi Chirag,

    not sure which web part you mean in detail but most web parts only use the SPWeb and SPSite objects from SPContext which are not allowed to be disposed.

    Cheers,

    Stefan

    Reply

  15. Hi Stefan,

    I am working in a sharepoint project in which there is a root site collection which contains other site collections e.g Info, so there is a data view web part created in SPD which targets the event calendar list which resides in Info site, so it is clear that in any way the SPD data view web part must create an object of Info site collection and get the root web object [this is not SPWeb object created from SPContext site object]. So in such scenario do the SPD data view web part disponses that SPSite and SPWeb objects automatically?

    Reply

  16. Hi Chirag,

    all site collections are independent. A site collection can contain sites – but not site collections.

    Cheers,

    Stefan

    Reply

  17. Chirag ~

    Since you’re not using code to create the DVWP, you wouldn’t have any way to Dispose() the objects even if you wanted to. I would hope the built-in controls would clean up after themselves, but in the worst case scenario since you’re only dealing with SPWeb objects from the context SPSite, they will be cleaned up when the context site collection is disposed.

    Keith

    Reply

  18. To Dispose Or Not To Dispose….That Is The Question

    Reply

  19. I found this nice problem! An SPRequest, allocated by SPContext.Current, wasn’t disposed! How is it possible?

    An SPRequest object was not disposed before the end of this thread.  To avoid wasting system resources, dispose of this object or its parent (such as an SPSite or SPWeb) as soon as you are done using it.  This object will now be disposed.  Allocation Id: {42853923-E532-4C15-B002-6BE9D4C6D727}  This SPRequest was allocated at    at Microsoft.SharePoint.Library.SPRequest..ctor()     at Microsoft.SharePoint.SPGlobal.CreateSPRequestAndSetIdentity(Boolean bNotGlobalAdminCode, String strUrl, Boolean bNotAddToContext, Byte[] UserToken, String userName, Boolean bIgnoreTokenTimeout, Boolean bAsAnonymous)     at Microsoft.SharePoint.SPWeb.InitializeSPRequest()     at Microsoft.SharePoint.SPWeb.EnsureSPRequest()     at Microsoft.SharePoint.SPWeb.get_Request()     at Microsoft.SharePoint.SPWeb.InitWebPublic()     at Microsoft.SharePoint.SPWeb.get_ID()     at Microsoft.SharePoint.SPContext.DefaultKey(HttpContext context, SPWeb web)     at Microsoft.SharePoint.SPContext.GetContext(HttpContext context)     at Microsoft.SharePoint.SPContext.get_Current() …

    Reply

  20. Hi Borcsok,

    looks as if the Microsoft.SharePoint.ApplicationRuntime.SPRequestModule is not registered in the http modules section of the web.config.

    Please double check.

    Cheers,

    Stefan

    Reply

  21. Hi Kit,

    yes it can reopen the SPWeb object.

    Cheers,

    Stefan

    Reply

  22. this is excellent post

    Reply

  23. Great Post!
    Thanks For Sharing:)

    Reply

  24. As I got the question about this recently: in SP2016,2019 and Subscription Edition the ULS tag is no longer “8l1n” – it is now “nask”.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.