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:

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

Comments (7)

  1. Matt Collinge says:

    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?

  2. drudolph says:

    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?

  3. jeromeL says:

    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

  4. Sanjay says:

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

  5. PD says:

    Nice blog! Thanks for posting it.

  6. Craig says:

    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

  7. Tj says:

    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.

Skip to main content