Free the SPWeb!
Every SharePoint developer knows that you need to free resources that you have used... like SPWeb (and others too!). Most often freeing up the resources are easily managed with the nice using -statement like this:
|
|
But you can do that stuff manually with try-finally + <object> .Displose(); . This is common .NET knowledge. But what happens if you don't do that? How much are we wasting resources if we just fail/forget to free objects? Well I tested this stuff a little bit and it was pretty suprising for me too... but before I'm going to give the results I'll show the examples I used:
|
|
This one is the "normal" way to use SPWeb and SPSite. I'll call this code 1.
|
|
This one is _really_ bad example. We're not disposing SPWeb at all! I call this code 2 (cool and creative naming right!)
If you run those examples in loop we can get following results (Time is measured in seconds and memory usage is in kilos):
Code 1 (good) | Code 2 (bad) | |||||||
Count | Time | Mem Usage | Peak Mem Usage | VM Size | Time | Mem Usage | Peak Mem Usage | VM Size |
10 | 1,42 | 37 512 | 37 512 | 36 792 | 1,53 | 42 220 | 42 220 | 44 132 |
100 | 1,67 | 37 456 | 37 456 | 36 808 | 4,41 | 71 932 | 87 656 | 91 028 |
500 | 2,90 | 37 532 | 37 532 | 36 880 | * | * | * | * |
1 000 | 5,00 | 37 612 | 37 612 | 36 888 | * | * | * | * |
10 000 | 33,38 | 35 400 | 37 524 | 35 724 | * | * | * | * |
Note: Memory consumption is just taken from Task Manager just after test code has finished. I haven't removed the test applications "base memory usage" (=usage before calling test code) but it was 8580K.
Note: The * indicates: Unhandled Exception: OutOfMemoryException.
So from numbers after the test run we can clearly see that code 2 is just slow and terrible memory slob! It can barely run few hundred loops before my server is "running low on memory". And if you look at the memory usage from task manager you'll see something that can't be seen from the table:
Upper image is code 2 and lower one is code 1. So after startup code 1 stays steady even if you're running loop > 1000. And in upper image you can see increasing memory usage. If the loop count is 100 or less (=No OutOfMemoryException is happening on my system) then memory decreases since all of that memory isn't used anymore and this cannot be seenfrom the table above. So the spike usage of code 2 is huge for even in < 100 loops. And if you're doing the same stuff over 1000 times it would suck up all memory you have in your system...
But if I have managed to scare you a little bit... that's good! But still don't start making too many disposes.... don't free up stuff that you haven't allocated yourself... like SPContext.Current.Web. It's allocated by SharePoint and if you dispose it you'll get exception. Here is example web part that will dispose if there is url parameter demanding it:
|
|
And if I add that web part to page and use it normally it works fine. But when I add "Dispose=true" to the url, it will give you:
Microsoft.SharePoint.SPException: Trying to use an SPWeb object that has been closed or disposed and is no longer valid.
So don't just free all disposable objects... think first but act second since if you don't act your application will definitely get those "Unhandled Exception: OutOfMemoryException" errors.
When you next time get OufOfMemoryException then check out your code before blaming the system... you might have some bugs in there.
Anyways... Happy hacking!
J
Comments
Anonymous
November 06, 2007
Very enlightening!! Shame the WSS developers don't follow this 'Best Practice'! I had some messages appearing in the trace log: 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. Turns out that the SPListEventProperties object creates an SPWeb object but never disposes of it! It has a Property Web (courtesy of Lutz Roeder's Reflector): public SPWeb Web { get { if (this.m_web == null) { while (this.WebUrl != null) { this.m_web = new SPSite(this.WebUrl).OpenWeb(); break; } } return this.m_web; } } Shouldn't SPListEventProperties implement IDispose?Anonymous
December 28, 2007
I'm getting the "An SPRequest object was not disposed before the end of this thread" message. However, it looks like the allocation spot is not in my code: This SPRequest was allocated at at Microsoft.SharePoint.Library.SPRequest..ctor() at Microsoft.SharePoint.SPGlobal.CreateSPRequestAndSetIdentity(Boolean bNotGlobalAdminCode, String strUrl, Boolean bNotAddToContext, Byte[] UserToken, Boolean bIgnoreTokenTimeout, Boolean bAsAnonymous) at Microsoft.SharePoint.SPWeb.InitializeSPRequest() at Microsoft.SharePoint.SPWeb.EnsureSPRequest() at Microsoft.SharePoint.SPWeb.get_Request() at Microsoft.SharePoint.SPListItemCollection.EnsureLis... 12/28/2007 08:23:51.65* w3wp.exe (0x1A10) 0x0CCC Windows SharePoint Services General 8l1n High ...tItemsData() at Microsoft.SharePoint.SPListItemCollection.Undirty() at Microsoft.SharePoint.SPBaseCollection.System.Collections.IEnumerable.GetEnumerator() at MYCODE" Where MYCODE is a code block that is looping (foreach) through an SPList.Item collection, hence the GetEnumerator call SPBaseCollection is making above. I get the list whose items I am looping through from code like: using (SPSite site = new SPSite(siteURL)) { using (SPWeb web = site.OpenWeb()) { return web.Lists[listName]; } } Is this OK? Is there anything I can do prevent this error?Anonymous
February 15, 2008
using (SPSite site = new SPSite(siteURL)) { using (SPWeb web = site.OpenWeb()) { return web.Lists[listName]; } } this code is not good at all since your method return a splist, which is dependent of your spweb and spsite and will prevent them from being disposed, or you'll have error as the parent object has been freed from memory you have to do all you operations on your list before you can dispose the web and site objectsAnonymous
April 21, 2008
This is my first comments Ilike these are all great story.Anonymous
June 26, 2008
Nice blog! Thanks for posting it.Anonymous
June 03, 2009
Nice post. By far the best posting I have seen on how to correctly dispose of sharepoint objects is at: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspxAnonymous
July 13, 2009
Hi, I hav'nt used any code. All I have done is just creating a site and adding some web parts to it. Then I got the error message "Trying to use the SPWeb object that has been disposed!!!" can someone explain this... Thank You.