First, I want to save anyone some reading and the quick answer to the error is… “SPLimitedWebPartManager opens up an SPWeb object behind the scenes which you don’t really know about.  So even though you wrap the SPLimitedWebPartManager in a Using {} block, your not actually disposing of that super secret SPWeb object behind the scenes, therefore you need to manually dispose of it, which is actually pretty easy”.

So if you care to know the back story here, I was hard at work on a custom wiki migration tool for a client when I got stumped for about 2 hours on “System.OutOfMemoryException: Server Out Of Memory”.  I had previously run the tool without any major errors but the client asked for a couple changes, namely they wanted a Document Library web part added to the bottom of every wiki page so that its easier for users to add files.  Adding web parts programmatically isn’t too hard so I dug up some previous code I wrote, threw it into my application, and about 15 minutes later I’d get .NET Out of Memory exception half way through the migration…which had previously worked fine.  Obviously the code I had added jacked something up, here is the error I was getting

ERROR 2009-07-22 14:08:22,274 - Error Getting sites wiki pages.  ERROR = System.OutOfMemoryException: Server Out Of Memory
 
There is no memory on the server to run your program. Please contact your administrator with this problem.
   at Microsoft.SharePoint.Library.SPRequestInternalClass.InitHeap(IntPtr&; pTlsHeapPtr)
   at Microsoft.SharePoint.Library.SPRequest.InitHeap(IntPtr&; pTlsHeapPtr)
   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.GetMetadataForUrl(String relUrl, Int32 mondoProcHint, Guid&; listId, Int32& itemId, Int32& typeOfObject, Object& fileOrFolder)
   at Microsoft.SharePoint.SPWeb.GetList(String strUrl)
   at .Program.AddDocLibWebPartToWikiPages(SPWeb web, String tabLevel) in C:\Program.cs:line 205

My first “fix”, since I was running in a VM, was to throw more memory at the VM.  I have 4 GBs on my laptop, so the most I could throw at the VM was 3 GBs, which I did and another 15 minutes later after rerunning the app, still got the same damn error.

I then checked my SPWeb/SPSite objects to make sure I was disposing of them properly.  I recalled awhile back reading that SPLimitedWebPartManager needs to be wrapped in a Using {} block as well, which I was already doing in the code below

foreach (SPListItem wikiPage in wikiPageList.Items)
{
    //look for the default page so we can mess with the web parts
    SPFile wikiPageFile = wikiPageList.RootFolder.Files[wikiPage.Url];
 
    if (log.IsDebugEnabled) log.Debug(tabLevel + "Wiki Page SPFile: " + wikiPageFile.Url);
 
    if (wikiPageFile != null)
    {
        //get the web part manager
        using (SPLimitedWebPartManager webPartMgr =
            wikiPageFile.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
        {
            //create doclib webpart
            ListViewWebPart docLibWebPart = new ListViewWebPart();
            docLibWebPart.Title = "Document Library";
            docLibWebPart.ListName = wikiFileList.ID.ToString("B").ToUpper();
            docLibWebPart.Hidden = false;
            docLibWebPart.Visible = true;
            docLibWebPart.ViewGuid = wikiFileList.DefaultView.ID.ToString("B").ToUpper();
 
            webPartMgr.AddWebPart(docLibWebPart, "Bottom", 0);
 
            if (log.IsDebugEnabled) log.Debug(tabLevel + "Added DocLib WebPart to : " + wikiPageFile.Url);
 
            wikiPageFile.Update();
        }
    }
}

I honestly couldn’t tell what I was doing wrong, so I hit the web to see what the deal might be and ran across the following three postings

Turns out that the SPLimitedWebPartManager opens up an SPWeb object behind the scenes which you don’t really know about.  So even though you wrap the SPLimitedWebPartManager in a Using {} block, your not actually disposing of that super secret SPWeb object behind the scenes, therefore you need to manually dispose of it, which is actually pretty easy, otherwise you’ll get “System.OutOfMemoryException: Server Out Of Memory” errors.  I added the dispose call to my code below

foreach (SPListItem wikiPage in wikiPageList.Items)
{
    //look for the default page so we can mess with the web parts
    SPFile wikiPageFile = wikiPageList.RootFolder.Files[wikiPage.Url];
 
    if (log.IsDebugEnabled) log.Debug(tabLevel + "Wiki Page SPFile: " + wikiPageFile.Url);
 
    if (wikiPageFile != null)
    {
        //get the web part manager
        using (SPLimitedWebPartManager webPartMgr =
            wikiPageFile.GetLimitedWebPartManager(System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
        {
            //create doclib webpart
            ListViewWebPart docLibWebPart = new ListViewWebPart();
            docLibWebPart.Title = "Document Library";
            docLibWebPart.ListName = wikiFileList.ID.ToString("B").ToUpper();
            docLibWebPart.Hidden = false;
            docLibWebPart.Visible = true;
            docLibWebPart.ViewGuid = wikiFileList.DefaultView.ID.ToString("B").ToUpper();
 
            webPartMgr.AddWebPart(docLibWebPart, "Bottom", 0);
 
            if (log.IsDebugEnabled) log.Debug(tabLevel + "Added DocLib WebPart to : " + wikiPageFile.Url);
 
            //BE SURE TO CALL DISPOSE ON THE SPLIMITEDWEBPARTMANAGERS WEB OBJECT THAT IT OPENS
            //BEHIND THE SCENES OTHERWISE YOU'LL GET OUT OF MEM EXCEPTIONS WHEN DOING LOTS OF LOOPING
            webPartMgr.Web.Dispose();
            
            wikiPageFile.Update();
        }
    }
}

Chances are if your only calling SPLimitedWebPartManager a few times you won’t really notice a problem, but when your doing THOUSANDS of loops like I was above, your going to hit some errors, but you still should dispose of the SPWeb object properly.

For shits and giggles I decided to run the “BAD” DLL through the MS SharePoint Dispose Best Practice Checker to see what it had to say (OK!!!! I know I should have this in my build process already!!!! Trust me it is now though after this debacle).  Honestly I didn’t think that the tool would catch it, but it actually did and here is the results that it spit back at me

ID: SPDisposeCheckID_160
Module: MindtouchFixup.exe
Method: MindtouchFixup.Program.AddDocLibWebPartToWikiPages(Microsoft.SharePoint.SPWeb,System.String)
Statement: webPartMgr := wikiPageFile.{Microsoft.SharePoint.SPFile}GetLimitedWebPartManager(1)
Source: C:\Program.cs
Line: 242
Notes: Dispose/Close was not called on SPLimitedWebPartManager.Web
More Information: http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx#SPDisposeCheckID_160

I’ve read Roger Lamb’s post quite a few times and knew about the SPLimitedWebPartManager, but I guess I never read carefully enough to know that I had to dispose of the web object it created, so had I FULLY read his post and best practices, I could have gotten 2-3hrs of my life back.

Moral of this whole story is to not only know when to dispose of SPWeb/SPSite objects, but to REALLY REALLY REALLY understand the when/why and know them by heart so that you don’t waste pointless time like I did. 


Posted in:   Tags:
Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2017 Tony Testa's World