Since I’ve been doing more and more code reviews and tracking down performance issues, I keep seeing the same category of “bad performance” development.
Before reading anything more — go check your ULS logs on production.
Pay close attention to errors like:
An SPRequest object was reclaimed by the garbage collector instead of being explicitly freed.An SPRequest object was not disposed before the end of this thread.Potentially excessive number of SPRequest objects (30) currently unreleased on thread 16.Detected use of SPRequest for previously closed SPWeb object.
These are not good. They’re a reliable indicator of performance issues.
What Is SPRequest?
Pavlov wrote a great deep-dive on what SPRequest actually is. Worth reading.
What Causes These Warnings?
Creating too many SPSite objects in a short time will trigger the “excessive number of SPRequest objects” warning. But the more common mistake is subtler.
Which of these two patterns is wrong?
Pattern A (Bad):
SPSite site = new SPSite(url);
SPWeb web = site.OpenWeb();
SPList list = web.Lists["MyList"];
site.Dispose();
web.Dispose();
// ... continue using `list` here
foreach (SPListItem item in list.Items) { ... }
Pattern B (Good):
using (SPSite site = new SPSite(url))
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["MyList"];
foreach (SPListItem item in list.Items) { ... }
}
Pattern A generates the SPRequest errors. Why?
Because you’re creating SPSite and SPWeb, getting the SPList reference, then disposing the parents — but continuing to use the SPList object after the parent is disposed. The list still holds a reference to the underlying SPRequest, but the parent context it belongs to is gone.
Pattern B is correct. Keep all usage of objects obtained from SPSite/SPWeb inside the using block.
Enabling Stack Traces in SP2013
In SharePoint 2013, the SPRequest warning includes this line:
To determine where this object was allocated, set
Microsoft.SharePoint.Administration.SPWebService.ContentService.CollectSPRequestAllocationCallStacks = true.
To enable this via PowerShell (script from Stefan Gossner’s blog):
$contentService = [Microsoft.SharePoint.Administration.SPWebService]::ContentService
$contentService.CollectSPRequestAllocationCallStacks = $true
$contentService.Update()
Once enabled, the ULS warnings will include a full stack trace showing exactly where the bad object was allocated — making it trivial to find the offending code.
The Golden Rule
Never dispose
SPSiteorSPWebwhile you still need objects obtained from them. Never use objects obtained from a disposedSPSite/SPWeb.
OK for a handful of users. When your solution is used by 50,000 users, this will cause serious performance degradation.
Further Reading
- MSDN: Best Practices for Using Disposable Windows SharePoint Services Objects
- How to Avoid the Top 5 SharePoint Performance Mistakes
- Troubleshooting SPSite/SPWeb Leaks in WSS v3 and MOSS 2007
Happy reading! 😊