SharePoint: Identifying memory problems introduced by custom code
SharePoint is a great platform that makes it easy to customize the portal view for users to their individual needs. Many times though the out of the box Features, Lists and Web Parts are not enough. So you either buy 3rd party extensions or you build your own. One specific problem area with SharePoint is memory. Especially when dealing with the SharePoint Object Model you can easily run into memory leaks. Why that? Isn’t it all managed code and shouldn’t the Garbage Collector take care of unused object? Well – that’s only partial true for SharePoint.The SharePoint Object Model explained
When you write your own Web Parts and if you want to access SharePoint data you have to use the SharePoint Object Model. The model provides an extensive list of managed objects to query your SharePoint webs, sites and lists. The core of SharePoint however is mostly implemented in native code which is wrapped by certain classes. Hristo Pavlov wrote a great article that explains the special wrapper class SPRequest which plays a very central role in the SharePoint Object Model.
Disposing SPWeb and SPSite
As you can read from Hristo’s and other blogs – it is essential to call Dispose or Close on certain objects that you get returned when working with the SharePoint Object Model. If you don’t do it – the Garbage Collector will not clean those objects which will lead to a memory issue over the long run. Not only is managed memory not freed – it’s mainly unmanaged memory that is referenced by those managed wrapper objects.
How to identify memory problems
The first thing you have to do is find out whether you have a memory problem or not. If your application pools constantly recycle because you exceeded your memory limit then its very likely that you have a memory issue. You can use a monitoring tool like Windows Performance Logs and Alerts to monitor the performance counters of your w3wp.exe worker processes. Make sure you look at Heap Size Gen0, Gen1, Gen2, Large Object Heap as well as GC Activations for Gen0, Gen1 and Gen2. Managed objects are allocated in Generation 0 are being promoted to higher generations when they could not be freed by a GC Run. If you see your Gen2 (which is the highest generation) constantly growing – you know you have objects that could not be freeded by the GC because somebody is still holding references to them. Here is a memory graph taken with dynaTrace:
How to locate Memory Problems
Knowing that there is a memory problem is the first step. Now its time to figure out where the problem actually is. In this blog I want to focus on those SharePoint classes that we know are very likely a problem when not disposed or closed. The approach that I will use can also be applied to any other .NET class.
dynaTrace offers different types of Memory Dumps:
- Simple allows you to get an overview of the number of instances of every individual class on the heap
- Extended allows you to analyze each object on the heap including size and dependencies to other objects. This allows you to walk the referrer tree to find out which objects are holding a reference to an object and which objects are referenced by a particular object
- Selective allows you to selectively focus on particular classes. Find out which objects are still on the heap and where those objects have been allocated
As I know which classes we want to selectively monitor I start with defining a Memory Sensor Rule:
The next step is that I schedule a selective memory dump that runs every couple of minutes. I can then take these dumps and compare them to find out if there are really objects that steadily grow.
We can now take a closer look at the last dump and analyze the objects of SPWeb and find out which method created the individual instances:
We can see that OpenWeb created those 13 remaining instances. The final step allows us to see where OpenWeb was called in context of a single request to a SharePoint page. We can see the call to OpenWeb and the object allocation in the PurePath:
We now know that the LookupWebPart is calling OpenWeb in its RenderNormal method. OpenWeb returns a new instance of SPWeb that we need to explicitely Dispose or Close.
You want to avoid memory leaks which lead to frequent recycling of the application pool worker processes. The impact is slower performance, potential loss of data and lower user satisfaction with your customized SharePoint solution. Avoiding can be done by following best practices and common coding guidlines. In case there are memory leaks that made it to the final product you want to make sure to find them. The above described approach is one that enables quick and easy analysis of leaking code.