SPLimitedWebPartManager Memory Leak?

Posted on 05. Jun, 2007 by in SharePoint

Have a look at the following code segment:

while(true)
{
    using (SPSite siteCollection =
        new SPSite("http://localhost"))
    using (SPWeb site =
        siteCollection.OpenWeb("/Marketing"))
    {
        SPFolder pagesFolder = site.GetFolder("Pages");

        foreach (SPFile page in pagesFolder.Files)
        {
            WL(page.Url);

            using (SPLimitedWebPartManager webPartManager =
                page.GetLimitedWebPartManager
                    (PersonalizationScope.Shared))
            {
            }
        }
    }
}

With this code segment I’m just connecting to a site and iterating over the page collection, grabbing and instance of the page’s SPLimitedWebPartManager as I go. Since SPLimitedWebPartManager implements the IDisposable pattern I am being a good citizen and wrapping its instantiation in a using {} block. The problem with this code segment is that this is what it does to the process memory:

image

Now, if I change the source code to this:

while(true)
{
    using (SPSite siteCollection =
        new SPSite("http://localhost"))
    using (SPWeb site =
        siteCollection.OpenWeb("/Marketing"))
    {
        SPFolder pagesFolder = site.GetFolder("Pages");

        foreach (SPFile page in pagesFolder.Files)
        {
            WL(page.Url);

            using (SPLimitedWebPartManager webPartManager =
                page.GetLimitedWebPartManager
                    (PersonalizationScope.Shared))
            {
                webPartManager.Web.Dispose();
            }
        }
    }
}

The memory picture looks much different now:

image

The only difference being the addition of an explicit Dispose() within the webPartManager using.

A look inside the SPFile.GetLimitedWebPartManager call reveals that it calls an internal GetLimitedWebPartManagerInternal() method on the SPFile SPWeb member variable. A closer look at this method shows the following code:

SPWeb web = this.Site.OpenWeb();
if (this.AllowUnsafeUpdates)
{
    web.AllowUnsafeUpdates = this.AllowUnsafeUpdates;
}
SPWebPartManager manager = web.GetWebPartManagerInternal(pageUrl, requestedView, forRender, includeHidden, out bytes);

We see here that a new SPWeb object is getting spun up, and in the call to GetWebPartManagerInternal an assignment is going to be made to the SPLimitedWebPartManager m_web member variable. If we look at the Dispose() implementation for SPLimitedWebPartManager, we see the following:

public void Dispose()
{
    if (!this.m_disposed)
    {
        if (this.m_manager != null)
        {
            this.m_manager.Dispose();
        }
    }
    else
    {
        return;
    }
    this.m_webParts = null;
    this.m_manager = null;
    this.m_disposed = true;
}

Nothing is being done to dispose of the m_web! If I explicitly dispose of m_web, then memory stays low.

Is anyone encountering the same?

Bookmark and Share

11 Responses to “SPLimitedWebPartManager Memory Leak?”

  1. Jason Fant

    08. Jun, 2007

    Interestingly enough, Tom Sallese and I attended a session at TechEd today covering the WSS object model. One of the things that the speaker covered as a little known “gotcha” was exactly what you are talking about. It appears that we are going to have to be really careful when playing with the SharePoint’s object model. Good looking out B.

    Reply to this comment
  2. Peter {faa780ce-0f0a-4c28-81d2-3667b71287fd}

    28. Sep, 2007

    Yes, this is exactly what I saw. It didn’t surprise me at all when I got my “outofmemoryexception”; I already had a healthy fear of SharePoint. :)

    Reply to this comment
  3. Shai

    24. Oct, 2007

    Hi,
    I fail to understand why you feel that disposing of the web part manager should also dispose its owner web?

    for instance, if you have code like this:
    spweb w = …..
    SPLimitedWebPartManager mgr = w.OpenFile(“…”).GetLimitedWebPartManager(…);
    mgr.AddWebPart(…);
    mgr.Dispose();

    w.Title += ” Done!”;
    w.Update();
    w.Dispose();

    See, I continue to work on the web object after disposing of the limited web part manager… It would be a bug if my w.TItle update will fail… no?

    Reply to this comment
  4. admin

    24. Oct, 2007

    The difference is that the web part manager is not using your w instance, it creates its own instance on the following line:

    SPWeb web = this.Site.OpenWeb();

    In your example you actually have 2 instances of SPWeb, you have your instance “w”, and then there is an instance encapsulated in the web part manager “web”. The web part manager should dispose of the “web” instance, not your “w” instance.

    Reply to this comment
  5. Incanna

    08. May, 2009

    ehh. interesting..

    Reply to this comment
  6. JessicaRich

    10. May, 2009

    Thanks for posting, definitely going to subscribe! See you on my reader.

    Reply to this comment
  7. ArianaSype

    13. May, 2009

    Wow! Thank you very much! I always wanted to write in my site something like that

    Reply to this comment
  8. Tudor Iliescu

    01. Nov, 2011

    Very interesting! It the same in 2010?

    Reply to this comment
    • bryan

      01. Nov, 2011

      From what I’ve seen, yes. I poked around in SPLimitedWebPartManager for 2010 and it still does not appear to close the SPWeb object that it opens up, so I would recommend still explicitly closing it. If anyone has seen differently in 2010 let me know!

      Reply to this comment
  9. Adrian Iurov

    18. Nov, 2011

    From what I’ve seen in the code, this is NOT a memory leak in SP2010.

    These 2 fields are part of the SPLimitedWebPartManager class:

    SPWeb m_web;
    SPWebPartManager m_manager;

    When Dispose() is called on SPLimitedWebPartManager, inside it calls m_manager.Dispose() which calls m_web.Dipose()

    The m_web of the SPWebPartManager instance references the same SPWeb instance as the m_web of the SPLimitedWebPartManager instance.

    In order to see that the 2 fields reference the same SPWeb instance, take a look at the way this m_web is opened inside SPWeb.GetLimitedWebPartManagerInternal. Later on is assigned to the m_web of a SPWebPartCollectionInitialState instance and in the end to the newly created SPWebPartManager instance.

    It’s a bit hard to follow, but if you need more details about the entire flow, I could provide them to you.

    Reply to this comment
    • bryan

      18. Nov, 2011

      Ah, you’re right Adrian! When I looked earlier I just took a quick glance at Dispose() and noticed it still wasn’t cleaning it up, but you’re right, it’s no longer creating the instance inside of SPLimitedWebPartManager, instead it’s point to an instance created by SPWebPartManager, and SPWebPartManager cleans up the SPWeb object.

      Thanks for the correction!

      Reply to this comment

Leave a Reply