Free the SPWeb!

Published 29 June 07 05:30 PM | jannemattila 

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:

1
2
3
4
5
6
7
using (SPSite site = new SPSite("http://localhost/"))
{
  using (SPWeb web = site.OpenWeb("/"))
  {
    // TODO: Do something funny
  }
}

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:

1
2
3
4
5
6
7
8
9
10
using (SPSite site = new SPSite("http://localhost/"))
{
  for (int i = 0; i < COUNT; i++)
  {
    using (SPWeb web = site.OpenWeb("/"))
    {
      // TODO: Do something funny
    }
  }
}

This one is the "normal" way to use SPWeb and SPSite. I'll call this  code 1.

 

1
2
3
4
5
6
7
8
9
using (SPSite site = new SPSite("http://localhost/"))
{
  for (int i = 0; i < COUNT; i++)
  {
    SPWeb web = site.OpenWeb("/");
    // TODO: Do something funny
    // Missing: web.Dispose();
  }
}

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:

1
2
3
4
5
6
7
protected override void Render(HtmlTextWriter writer)
{
  if (this.Page.Request["Dispose"] != null)
  {
    SPContext.Current.Web.Dispose();
  }
}

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

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Matt Collinge said on November 6, 2007 10:07 AM:

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?

# drudolph said on December 28, 2007 11:04 AM:

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?

# jeromeL said on February 15, 2008 9:16 AM:

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 objects

# Sanjay said on April 21, 2008 9:37 AM:

This is my first comments Ilike these are all great story.

# PD said on June 26, 2008 12:12 PM:

Nice blog! Thanks for posting it.

# Craig said on June 4, 2009 7:54 AM:

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

Leave a Comment

(required) 
(optional)
(required) 
Page view tracker