There are several articles around discussing the dispose of SPWeb and SPSite objects, e.g.:
- SharePoint 2007 and WSS 3.0 Dispose Patterns by Example from Roger Lamb
- Best Practices: Using Disposable Windows SharePoint Services Objects from Scott Harris and Mike Ammerlaan
- Best Practices: Common Coding Issues When Using the SharePoint Object Model from Scott Harris and Mike Ammerlaan
And also in a couple of articles I wrote myself:
- Dealing with Memory Pressure problems in MOSS/WSS
- Troubleshooting SPSite/SPWeb leaks in WSS v3 and MOSS 2007
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.
Permalink
PingBack from http://solutionizing.net/2008/12/06/the-new-definitive-spsitespweb-disposal-article/
Permalink
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.
Permalink
excellent write up mate, thanks!
Permalink
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
Permalink
Hi Rick,
yes this call will construct a new SPWeb object which you actually have to dispose.
Cheers,
Stefan
Permalink
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
Permalink
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
Permalink
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
Permalink
Hi Keith,
intersting. I will check into this in more detail tomorrow and post my results.
Cheers,
Stefan
Permalink
Linki, które posłużyły mi przy tworzeniu prezentacji, z których czerpałem wiedzę, nakładałem ją na to
Permalink
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
Permalink
Hey Stefan ~
I’ve posted a revision of my disposal article on the SharePoint Dev Wiki here:
http://sharepointdevwiki.com/display/public/When+to+Dispose+SharePoint+objects
I’d appreciate if you could look it over for anything incorrect or omitted.
Thanks ~
Keith
Permalink
Chances are that by now if you have been developing on the Microsoft SharePoint Office Server (MOSS)
Permalink
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?
Permalink
SPSite and SPWeb implement the IDisposable interface
Permalink
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
Permalink
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?
Permalink
Hi Chirag,
all site collections are independent. A site collection can contain sites – but not site collections.
Cheers,
Stefan
Permalink
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
Permalink
To Dispose Or Not To Dispose….That Is The Question
Permalink
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() …
Permalink
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
Permalink
Stefan,
If I open an SPWeb and use it to get a SPListItemCollection, does the SPListItemCollection count as a "child object"? If I use that collection after disposing of the SPWeb object that was used to retrieve it, would the SPWeb be reopened?
Thanks,
Kit
(see my question here for more info http://stackoverflow.com/questions/1394952/will-using-a-splistitemcollection-returned-from-a-function-reopen-the-spweb)
Permalink
Hi Kit,
yes it can reopen the SPWeb object.
Cheers,
Stefan
Permalink
this is excellent post
Permalink
Great Post!
Thanks For Sharing:)
Permalink
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”.