Using Disposable Windows SharePoint Services Objects

原文链接:http://msdn.microsoft.com/en-us/library/aa973248.aspx

 

Summary: Learn the appropriate ways to write your code when using Microsoft Windows SharePoint Services objects so that you can avoid retaining the objects in memory with the Microsoft .NET Framework. (24 printed pages)

Scott Harris, Microsoft Corporation

Mike Ammerlaan, Microsoft Corporation

June 2006

Updated: November 2006

Applies to: Microsoft Windows SharePoint Services 3.0, Microsoft Windows SharePoint Services 2.0, Microsoft Office SharePoint Server 2007, Microsoft Office SharePoint Portal Server 2003

Contents:

Introduction to Using Disposable Windows SharePoint Services Objects

The objects in the Microsoft Windows SharePoint Services 3.0 object model serve as an interface for working with Windows SharePoint Services data and configuration. Frequently, developers call into the object model to read or write new data in the Windows SharePoint Services store.

The Windows SharePoint Services object model contains objects that implement the IDisposable interface. You must take precautions when using these objects to avoid their long-term retention in memory in the Microsoft .NET Framework. Specifically, you should explicitly dispose of those SharePoint objects when you are finished using them.

In scenarios in which you use SharePoint objects extensively—for example, in SharePoint sites that use custom Web Parts—you can cause the following unusual behaviors by not disposing of those objects that can be disposed of:

  • Frequent recycles of the Microsoft Windows SharePoint Services application pool, especially during peak usage

  • Application crashes that appear as heap corruption in the debugger

  • High memory use for Microsoft Internet Information Services (IIS) worker processes

  • Poor system and application performance

This article serves as a guide to the proper procedures for handling and disposing of SharePoint objects.

Background

Several of the Windows SharePoint Services objects, primarily the SPSite class and SPWeb class objects, are created as managed objects. However, these objects use unmanaged code and memory to perform the majority of their work. The managed part of the object is small; the unmanaged part of the object is much larger. Because the smaller managed part of the object does not put memory pressure on the garbage collector, the garbage collector does not release the object from memory in a timely manner. The object's use of a large amount of unmanaged memory can cause some of the unusual behaviors described earlier. Calling applications that work with IDisposable objects in Windows SharePoint Services must dispose of the objects when the applications finish using them. You should not rely on the garbage collector to release them from memory automatically.

Finding Incorrectly Disposed Objects

You can identify the potential presence of incorrectly disposed objects by asking the following questions:

  1. Does your application pool recycle frequently, especially under heavy loads?

    This assumes that the application pool is set to recycle when a memory threshold is reached. The memory threshold should be between 800 MB and 1.5 GB (assuming you have 2 GB or more of RAM). Setting the recycle of the application pool to occur closer to 1 GB gives the best results, but you should experiment to see what settings work best for your environment. If the recycle setting is too low, you will experience performance issues because of frequent application pool recycles. If the setting is too high, your system will begin to experience performance problems because of page swapping, memory fragmentation, and other issues.

  2. Does your system perform poorly, especially under heavy loads?

    As memory usage begins to increase the system must compensate, for example, by paging memory and handling memory fragmentation.

  3. Does your system crash or do users experience unexpected errors such as timeouts or page-not-available errors, especially under heavy loads?

    Again, when memory utilization gets high or fragmented, some functions can fail because they cannot allocate memory for other operations. In many cases, the code does not properly handle the "out of memory" exception, which leads to false or misleading errors.

  4. Does your system use custom or third-party Web Parts or custom applications?

    Many developers are not aware that they must dispose of SharePoint objects and why. They assume that garbage collection performs this function automatically, but that is not true in all cases.

If you answer "yes" to number 4, and to one or more of the other questions, there is a good chance that your custom code is not disposing of items properly.

If your sites are displaying any of the unusual behaviors described above, you can determine whether the cause is a memory leak due to incorrectly disposed objects by checking the ULS logs for entries related to the SPRequest object. Each instance of SPSite and SPWeb contains a reference to an SPRequest object that, in turn, contains a reference to an unmanaged COM object that handles communications with the database server. Windows SharePoint Services monitors the number of SPRequest objects that exist in each thread, and in parallel threads, and places useful entries into the logs under the three following scenarios:

  • The total number of SPRequest objects exceeds a configurable threshold.

  • An SPRequest object continues to exist at the end of a thread.

  • An SPRequest object has been garbage collected.

The first scenario will occur most frequently, especially if your site uses the default threshold value of 8 SPRequest objects. Whenever the number of SPRequest objects exceeds this threshold, the following entry appears in the ULS logs:

Potentially excessive number of SPRequest objects (number of objects) currently unreleased on thread number of thread. Ensure that this object or its parent (such as an SPWeb or SPSite) is being properly disposed. Allocation Id for this object: {GUID}

The desired threshold will vary according to the nature of your site and the applications running on it. When your sites are experiencing problems with performance, you should monitor your installation’s ULS logs in order to understand how many SPRequest objects your site applications are creating. This will help you determine whether the designs of your sites and applications are causing too many SPRequest objects to be created. Even if incorrect disposal of objects is not the cause of your performance problem, you may need to redesign your sites or custom site applications in order to reduce overall memory consumption caused by excessive proliferation of SPRequest objects.

Since the very low default threshold may not apply to many sites, you can change this threshold by editing the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings LocalSPRequestWarnCount = desired threshold value

Once you have determined that incorrect disposal of objects might be causing SPRequest objects to proliferate and unnecessarily increase the memory footprint of your sites, you can find specific instances of incorrect disposal by looking for the following two entries, which relate to the number and state of SPRequest objects on a single thread:

  • 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. This object will now be disposed. Allocation Id: {GUID}To determine where this object was allocated, create a registry key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings. Then create a new DWORD named SPRequestStackTrace with the value 1 under this key.

  • An SPRequest object was reclaimed by the garbage collector instead of being explicitly freed. 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. Allocation Id: {GUID} To determine where this object was allocated, create a registry key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings. Then create a new DWORD named SPRequestStackTrace with the value 1 under this key.

The first message indicates that an SPRequest object was disposed because it still existed at the end of a thread. The second message indicates that the garbage collector disposed of an SPRequest object. Both messages point to cases where memory is being wasted because of incorrect disposal of Windows SharePoint Services objects.

In order to identify the code that is responsible for the problem, you can either search in the logs for the allocation ids that appear in the log entries or follow the instructions mentioned in the warnings and add the following registry key setting:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings SPRequestStackTrace = 1

This registry key setting ensures that the stack trace of the original SPRequest allocation (which occurs whenever an SPSite or SPWeb object is created) is added to the logs whenever these warnings occur.

You can use any of several coding techniques to fix or avoid this sort of problem and ensure that the objects are disposed of properly. We discuss them in the following sections.

Coding Techniques

You can take advantage of certain coding techniques to ensure that objects are disposed of. These techniques include using the following in your code:

  • Dispose method

  • using clause

  • try, catch, and finally blocks

Dispose vs. Close Method Usage

The Dispose and Close methods for the SPWeb object and SPSite object function in the same way. The Dispose method simply calls the object's Close method. We recommend calling the Dispose method, instead of Close, for the following reasons:

  • SPWeb and SPSite objects implement the IDisposable interface, and the standard .NET Framework process calls the Dispose method to free from memory any resources associated with the object.

  • Future releases of your code are ensured to be called properly.

using Clause

You can automatically dispose of SharePoint objects that implement the IDisposable interface by using the Microsoft Visual C# using clause.

The following code provides an example.

String str;
using(SPSite oSPsite = new SPSite("http://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
}
}

try/catch/finally Blocks

The following is a recommendation of how to code try/catch/finally blocks. When you use try blocks, it is important to add a finally block to ensure that all objects are properly disposed of.

Any code that is ultimately contained within a try { } catch { } block should have a governing finally clause, which ensures that the respective objects are disposed of. These try { } catch { } blocks can exist outside of the function where you use SharePoint objects. In those cases, you should consider using try/catch/finally in the methods to wrap your usages of the SharePoint object model directly.

String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("http://server");
oSPWeb = oSPSite.OpenWeb(..);
str = oSPWeb.Title;
}
catch(Exception e)
{
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
}

Calling Response.Redirect WILL NOT execute the finally block. Therefore, before any redirection or transfer of processing can occur, you must dispose of the objects. For example, if your code must redirect, implement it in a way similar to the following.

String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("http://server");
oSPWeb = oSPSite.OpenWeb(..);
str = oSPWeb.Title;
if(bDoRedirection)
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
Response.Redirect("newpage.aspx");
}
}
catch(Exception e)
{
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
}

Recommendations to Reduce Long-Term Object Retention

To reduce long-term retention of Windows SharePoint Services objects, we offer the following general recommendations.

  1. If you create the object with a new operator, the creating application must dispose of it.

    Good Coding Practice #1

    SPSite oSPSite = new SPSite("http://server");
        ... additional processing on SPSite ...
        oSPSite.Dispose();
        

    Good Coding Practice #2

    using (SPSite oSPSite = new SPSite("http://server"))
        {
        ... additional processing on SPSite ...
        }
        
  2. SharePoint methods that return other SPWeb objects (such as SPSite.OpenWeb) create new items and should be disposed of.

    Good Coding Practice #1

    String str;
        SPSite oSPSite = new SPSite("http://server");
        SPWeb oSPWeb = oSPSite.OpenWeb();
        str = oSPWeb.Title;
        str = oSPWeb.Url;
        ... additional processing on SPWeb ...
        oSPWeb.Dispose();
        oSPSite.Dispose();
        

    Good Coding Practice #2

    String str;
        using(SPSite oSPSite = new SPSite("http://server"))
        {
        using(SPWeb oSPWeb = oSPSite.OpenWeb())
        {
        str = oSPWeb.Title;
        str = oSPWeb.Url;
        ... additional processing on SPWeb ...
        }
        }
        

SPSite Objects

This section describes the situations in which new SPSite objects are returned and must be disposed of.

In general, any time a calling application uses the new SPSite() constructors (any signature), it should call the SPSite.Dispose() method when it is finished using the object. If the SPSite object is obtained from SPControl.GetContextSite, the calling application should NOT dispose of the object. Because the SPWeb and SPSite objects keep an internal list that is derived in this way, disposing of the object may cause the SharePoint object model to behave unpredictably. Internally, Windows SharePoint Services enumerates over this list after page completion to dispose of the objects properly.

SPSiteCollection Class

This section describes the methods, properties, or operators in the SPSiteCollection object that require the returned SPSite object to be closed after access.

SPSiteCollection.Add Method

The SPSiteCollection.Add method creates and returns a new SPSite object. You should dispose of any SPSite object returned from the SPSiteCollection.Add method.

Good Coding Practice #1

SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
SPSite oSPSite = aSites.Add( ... );
... Process the site info ...
oSPSite.Dispose();
oSPGlobalAdmin.Dispose();

Good Coding Practice #2

SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
using(SPSite oSPSite = aSites.Add( ... ))
{
... Process the site info ...
}
oSPGlobalAdmin.Dispose();

SPSiteCollection [ ] Index Operator

The SPSiteCollection [] index operator returns a new SPSite object for each access. An SPSite instance is created even if that object has already been accessed. The following code samples demonstrate improper disposal of the SPSite object.

Bad Coding Practice #1

int i;
SPSite oSPSite;
SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
for (i = 0;i < aSites.Count;i++)
{
oSPSite = aSites[i];
BuildTableRow(oDisplayTable, "Site", oSPSite.Url);
}
oSPGlobalAdmin.Dispose();

Bad Coding Practice #2

SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
foreach(SPSite oSPSite in aSites)
{
BuildTableRow(oDisplayTable, "Site", oSPSite.Url);
}
oSPGlobalAdmin.Dispose();

The recommended fix is to place a Dispose() at the end of each loop.

Good Coding Practice #1

int i;
SPSite oSPSite;
SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
for(i = 0;i < aSites.Count;i++)
{
oSPSite = aSites[i];
BuildTableRow(oDisplayTable, "Site", oSPSite.Url);
oSPSite.Dispose();
}
oSPGlobalAdmin.Dispose();

Good Coding Practice #2

SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
foreach(SPSite oSPSite in aSites)
{
BuildTableRow(oDisplayTable, "Site", oSPSite.Url);
oSPSite.Dispose();
}
oSPGlobalAdmin.Dispose();

Good Coding Practice #3

int i;
SPGlobalAdmin oSPGlobalAdmin    = new SPGlobalAdmin();
SPSiteCollection aSites         = oSPGlobalAdmin.VirtualServers[0].Sites;
for(i = 0;i < aSites.Count;i ++)
{
using(SPSite oSPSite = aSites[i])
{
BuildTableRow(oDisplayTable, "Site", oSPSite.Url);
}
}
oSPGlobalAdmin.Dispose();

SPSite.AllWebs Property (SPWebCollection)

This section describes the methods, properties, or operators in the SPSite.AllWebs property collection that require the SPWeb object to be closed after access.

SPSites.AllWebs.Add Method

The SPSite.AllWebs.Add method(or SPWebCollection.Add) creates and returns an SPWeb object. You should dispose of any SPWeb object returned from SPSite.AllWebs.Add.

Good Coding Practice #1

SPWeb oSPWeb;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.AllWebs.Add( ... );
... Process the SPWeb info ...
oSPWeb.Dispose();

Good Coding Practice #2

SPSite oSPSite = SPControl.GetContextSite(Context);
using(SPWeb oSPWeb = oSPSite.AllWebs.Add( ... ))
{
... Process the SPWeb info ...
}
NoteNote:

The SPSite object was obtained from the GetContextSite() method and does not need to be disposed of.

SPSite.AllWebs [ ] Index Operator

The SPSite.AllWebs [] index operator returns a new SPWeb instance each time it is accessed. An object is created during the indexing operation even if that object has already been accessed. If not properly closed, the following code samples leave an SPWeb object in the .NET Framework garbage collector.

Bad Coding Practice #1

int i;
SPWeb oSPWeb;
SPSite oSPSite = SPControl.GetContextSite(Context);
for(i=0;i < oSPSite.AllWebs.Count; i++)
{
oSPWeb = oSPSite.AllWebs[i];
BuildTableRow(oDisplayTable, "Web", oSPWeb.Title);
}

Bad Coding Practice #2

SPSite oSPSite = SPControl.GetContextSite(Context);
foreach(SPWeb oSPWeb in oSPSite.AllWebs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb.Title);
}

The recommended way to fix this is to place Dispose() at the end of each loop.

Good Coding Practice #1

int i;
SPWeb oSPWeb;
SPSite oSPSite = SPControl.GetContextSite(Context);
for(i = 0;i < oSPSite.AllWebs.Count; i++)
{
oSPWeb = oSPSite.AllWebs[i];
BuildTableRow(oDisplayTable, "Web", oSPWeb.Title);
oSPWeb.Dispose();
}

Good Coding Practice #2

SPSite oSPSite = SPControl.GetContextSite(Context);
foreach(SPWeb oSPWeb in oSPSite.AllWebs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb.Title);
oSPWeb.Dispose();
}

Good Coding Practice #3

int i;
SPWeb oSPWeb;
SPSite oSPSite = SPControl.GetContextSite(Context);
for(i = 0;i < oSPSite.AllWebs.Count; i++)
{
using(oSPWeb = oSPSite.AllWebs[i])
{
BuildTableRow(oDisplayTable, "Web", oSPWeb.Title);
}
}

SPSite.OpenWeb and SPSite. SelfServiceCreateSite Methods

The SPSite.OpenWeb method and SPSite.SelfServiceCreateSite method (all signatures) create an SPWeb object and return it to the caller. This new object is not stored in the SPSite object and is not disposed of anywhere in the SPSite class. For this reason, you should dispose of any object created via these methods.

Good Coding Practice #1

SPSite oSPSite = new SPSite("http://Server");
SPWeb oSPWeb = oSPSite.OpenWeb(..);
... additional processing ...
oSPWeb.Dispose();
oSPSite.Dispose();

Good Coding Practice #2

using(SPSite oSPSite = new SPSite("http://Server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb(..))
{
... additional processing ...
}
}

SPSite.LockIssue, SPSite.Owner, and SPSite.SecondaryContact Properties

The following properties reference data from the top-level Web site and use the SPSite.RootWeb property:

For more information, see the discussion of SPSite.RootWeb. If you use any of these respective properties, you must call the Dispose method on the SPSite.RootWeb property.

Good Coding Practice #1

String str;
SPSite oSPSite = new SPSite("http://server");
str = oSPSite.LockIssue;
oSPSite.RootWeb.Dispose();
oSPSite.Dispose();

Good Coding Practice #2

String str;
using(SPSite oSPSite = new SPSite("http://server"))
{
str = oSPSite.Owner;
oSPSite.RootWeb.Dispose();
}

SPSite.RootWeb Property

The first time the SPSite.RootWeb property is called, the property determines whether a member variable is assigned with a non-null value. If the member variable is null, a new SPWeb object is created by calling SPSite.OpenWeb method and assigns the new SPWeb object to the member variable. The next call to the SPSite.RootWeb property simply returns the value that was stored in the member variable.

The calling application should dispose of the SPSite.RootWeb property just before disposing of the SPSite object that is using it, as shown in the following example.

Good Coding Practice #1

String str;
SPSite oSPSite = new SPSite("http://server");
str = oSPSite.RootWeb.Title;
... additional processing ...
oSPSite.RootWeb.Dispose();
oSPSite.Dispose();

Good Coding Practice #2

String str;
using(SPSite oSPSite = new SPSite("http://server"))
{
str = oSPSite.RootWeb.Title;
... additional processing ...
oSPSite.RootWeb.Dispose();
}

Good Coding Practice #3

String str;
using(SPSite oSPSite = new SPSite("http://server"))
{
using(SPWeb oRootWeb = oSPSite.RootWeb)
{
str = oRootWeb.Title;
... additional processing ...
}
}

SPWeb Objects

This section describes the situations in which SPWeb objects are returned and may need to be disposed of.

SPWeb.ParentWeb Property

The first time the SPWeb.ParentWeb property is called, it determines whether a member variable is assigned with a non-null value. If the member variable is null, a new SPWeb object is created if a valid parent Web site exists by calling the OpenWeb method, and assigns the new SPWeb object to the member variable. The next call to the SPWeb.ParentWeb property simply returns the value that was stored in the member variable.

The calling application should dispose of the SPWeb.ParentWeb property just before disposing the SPWeb object that is using it. Following are examples.

Good Coding Practice #1

String str;
SPSite oSPSite = new SPSite("http://server");
SPWeb oSPWeb, oSPWebParent;
oSPWeb       = oSPSite.OpenWeb();
oSPWebParent = oSPWeb.ParentWeb;
if (oSPWebParent != null)
{
... additional processing ...
}
if (oSPWebParent != null)
oSPWebParent.Dispose();
oSPWeb.Dispose();
oSPSite.Dispose();

Good Coding Practice #2

String str;
SPWeb oSPWeb, oSPWebParent;
using(SPSite oSPSite = new SPSite("http://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
oSPWebParent = oSPWeb.ParentWeb;
if(oSPWebParent != null)
{
... additional processing ...
}
If(oSPWebParent != null)
oSPWebParent.Dispose();
}
}

SPWeb.Webs Property (SPWebCollection)

This section describes the methods, properties, or operators in the SPWeb.Webs property collection that require disposal of the SPWeb object after access.

SPWeb.Webs.Add

The SPWeb.Webs.Add method (or SPWebCollection.Add) creates and returns a new SPWeb object. You should dispose of any SPWeb object returned from this method call.

Good Coding Practice #1

SPWeb oSPWeb
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPSWeb = oSPSite.AllWebs.Add( ... );
... Process the SPWeb info ...
oSPWeb.Dispose();

Good Coding Practice #2

SPSite oSPSite = SPControl.GetContextSite(Context);
using(SPWeb oSPSWeb = oSPSite.AllWebs.Add( ... ))
{
... Process the SPWeb info ...
}
NoteNote:

The SPSite object was obtained from the GetContextSite() method and does not need to be disposed of.

SPWeb.Webs[ ] Index OperatorH9

The SPWeb.Webs [] index operator returns a new SPWeb for each access. A new SPWeb is created by calling the OpenWeb method even if that object has already been accessed. The following code samples cause long-term retention of these objects in memory used by the .NET Framework.

Bad Coding Practice #1

int i;
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
for(i = 0;i < oSPWeb.Webs.Count;i++)
{
oSPWeb2 = oSPWeb.Webs[i];
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}

Bad Coding Practice #2

SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
foreach(SPWeb oSPWeb2 in oSPWebe.Webs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}

The recommended fix is to place a close at the end of each loop.

Good Coding Practice #1

int i;
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
for(i = 0;i < oSPWeb.Webs.Count;i++)
{
oSPWeb2 = oSPWeb.Webs[i];
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
oSPWeb2.Dispose();
}
oSPWeb.Dispose();

Good Coding Practice #2

SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
foreach(SPWeb oSPWeb2 in oSPWeb.Webs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
oSPWeb2.Dispose();
}
oSPWeb.Dispose();

Good Coding Practice #3

int i;
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
using(oSPWeb = oSPSite.OpenWeb())
{
for(i = 0;i < oSPWeb.Webs.Count;i++)
{
Using(oSPWeb2 = oSPWeb.Webs[i])
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}
}
}

Other Objects that Require Disposal

This section describes when to call the Dispose method on other SharePoint objects.

Microsoft.SharePoint.Portal.SiteData.Area.Web Property

The Area.Web property returns a new SPWeb object each time it is accessed. Any use of the Area.Web property should have a corresponding call to the Dispose method.

Bad Coding Practice #1

String str;
Area oArea = AreaManager.GetArea(PortalContext.Current, new Guid(AreaGiud);
str = oArea.Web.Title;   // Web is not reclaimed
str = oArea.Web.Url   // Web is not reclaimed

Good Coding Practice #1

String str;
Area oArea = AreaManager.GetArea(PortalContext.Current,
new Guid(AreaGiud);
SPWeb oSPWeb = oArea.Web;
str = oSPweb.Title;
str = oSPWeb.Url;
...
oSPWeb.Dispose();

Good Coding Practice #2

String str;
Area oArea = AreaManager.GetArea(PortalContext.Current, new
Guid(AreaGiud);
using(SPWeb oSPWeb = oArea.Web)
{
str = oSPweb.Title;
str = oSPWeb.Url;
}

SPControl.GetContextSite and SPControl.GetContextWeb Methods

If the object is obtained from the SharePoint context objects (SPControl.GetContextSite method and SPControl.GetContextWeb method), the calling application should NOT call the Dispose method on the object. Doing so may cause the SharePoint object model to behave unpredictably or fail. This is due to an internal list that is kept in the SPSite and SPWeb objects derived in this way. Internally, the object model enumerates over this list after page completion to dispose of the objects properly.

You should still dispose of an object that is created from these objects, for example, if a Web site is opened from an SPSite object that you obtained by using the SPControl.GetContextSite method.

Bad Coding Practice #1

SPSite oSPSite = SPControl.GetContextSite(..);
... additional processing ...
oSPSite.Dispose();
// Could cause problems in the SharePoint object model 

Good Coding Practice #1

SPSite oSPSite = SPControl.GetContextSite(..);
SPWeb oSPWeb = oSPSite.OpenWeb(..);
... additional processing ...
oSPWeb.Dispose();

Good Coding Practice #2

SPSite oSPSite = SPControl.GetContextSite(..);
using(SPWeb oSPWeb = oSPsite.OpenWeb())
{
... additional processing ...
}

WebPartPage.RootWeb Property

The WebPartPage.RootWeb property is similar to the SPSite.RootWeb property in that the first time the property is called, it determines whether a member variable is assigned with a non-null value. If the member variable is null, a new SPWeb object is created by calling the SPSite.OpenWeb method; the new SPWeb object is assigned to the member variable, or the member variable is assigned to WebPartPage.Web if that SPWeb object is a top-level Web site.

The calling application should dispose of the WebPartPage.RootWeb property only if WebPartPage.IsRootWeb returns true.

Good Coding Practice #1

String str;
WebPartPage oWebPartPage = new WebPartPage();
str = oWebPartPage.RootWeb.Title;
... additional processing ...
if(oWebPartPage.Web.IsRootWeb
oWebPartPage.Dispose();

Conclusion

Many SharePoint objects implement the IDisposable interface, so you must take care when using these SharePoint objects to avoid retaining them in memory. By following the guidelines for their disposal, as described in this article, you can help to ensure reliability of your Windows SharePoint Services customizations.

Acknowledgements

We would like to thank the following people for their input and guidance in creating this document:

  • Keith Richie, Microsoft Corporation

  • Rob Anderson, Microsoft Corporation

  • Steve Sheppard, Microsoft Corporation

  • Chris Gideon, Microsoft Corporation

  • Kelvin Lo, Microsoft Corporation

  • Rashid Aga, Microsoft Corporation

For more information on this and other SharePoint issues, see Keith Richie's blog.

Additional Resources

posted on 2009-01-08 08:47  王丹小筑  阅读(440)  评论(0)    收藏  举报

导航