Verwerfen von Objekten
Letzte Änderung: Donnerstag, 8. April 2010
Gilt für: SharePoint Foundation 2010
Inhalt dieses Artikels
Einführung in die Verwendung verwerfbarer SharePoint-Objekte
Auffinden von fälschlicherweise verworfenen Objekten
Codiertechniken für das ordnungsgemäße Verwerfen von Objekten
SPSite-Objekte
SPWeb-Objekte
Sonstige Objekte, die verworfen werden müssen
Schlussbemerkung
Einführung in die Verwendung verwerfbarer SharePoint-Objekte
Die Objekte in den Objektmodellen von Microsoft SharePoint Foundation 2010 und Microsoft SharePoint Server 2010 dienen als Schnittstelle für SharePoint Foundation-Daten. Entwickler rufen das Objektmodell häufig auf, um Daten aus den Datenspeichern von SharePoint Foundation 2010 und SharePoint Server 2010 zu lesen bzw. neue Daten in die Datenspeicher zu schreiben.
Die SharePoint Foundation 2010- und SharePoint Server 2010-Objektmodelle enthalten Objekte, die die IDisposable-Schnittstelle implementieren. Bei der Verwendung dieser Objekte müssen Sie mit Bedacht vorgehen, um eine langfristige Aufbewahrung im Arbeitsspeicher in Microsoft .NET Framework zu vermeiden.
Insbesondere sollten Sie jene SharePoint-Objekte nach ihrer Verwendung explizit verwerfen, die IDisposable implementieren.
In Szenarien, in denen SharePoint-Objekte umfassend eingesetzt werden, wie z. B. in SharePoint-Websites, die benutzerdefinierte Webparts verwenden, kann dies die folgenden ungewöhnlichen Verhaltensweisen zur Folge haben, wenn SharePoint-Objekte nach ihrer Verwendung nicht verworfen werden.
Häufige Wiederverwendung des SharePoint Foundation-Anwendungspools, vor allem in Zeiten hoher Auslastung
Abstürze, die als Heapbeschädigung im Debugger angezeigt werden.
Hohe Arbeitsspeicherbelastung für Arbeitsprozesse der Internetinformationsdienste (Internet Information Services, IIS)
Schlechte System- und Anwendungsleistung
Dieser Artikel dient als Leitfaden für das richtige Behandeln und Verwerfen von SharePoint-Objekten, die IDispose implementieren. Die in diesem Artikel beschriebenen Probleme werden auch von SharePoint Dispose Checker Tool markiert. Dieses als Download verfügbare, kostenlose Programm überprüft Ihre Assemblys auf Codierpraktiken, die zu Arbeitsspeicherverlusten aufgrund von unzureichendem Verarbeiten und Verwerfen von SharePoint-Objekten führen.
Gründe für das Verwerfen von Objekten
Einige der SharePoint Foundation-Objekte, vorrangig die SPSite-Klassen und die SPWeb-Klassenobjekte, werden als verwaltete Objekte erstellt. Diese Objekte verwenden jedoch nicht verwalteten Code und Arbeitsspeicher für einen wesentlichen Teil ihrer Arbeit. Der verwaltete Teil des Objekts ist viel kleiner als der nicht verwaltete Teil. Da der kleinere verwaltete Teil keine hohe Arbeitsspeicherbelastung für den Garbage Collector darstellt, gibt der Garbage Collector das Objekt nicht innerhalb eines angemessenen Zeitraums aus dem Arbeitsspeicher frei. Da das Objekt in hohem Maß nicht verwalteten Arbeitsspeicher beansprucht, kann dies die weiter oben genannten ungewöhnlichen Verhaltensweisen zur Folge haben. Beim Aufrufen von Anwendungen, die IDisposable-Objekte in SharePoint Foundation einsetzen, müssen die Objekte verworfen werden, sobald die Anwendungen diese Objekte nicht mehr benötigen. Verlassen Sie sich nicht darauf, dass der Garbage Collector diese automatisch aus dem Arbeitsspeicher freigibt.
Auffinden von fälschlicherweise verworfenen Objekten
Anhand der folgenden Fragen können Sie feststellen, ob fälschlicherweise verworfene Objekte vorhanden sind:
Wird Ihr Anwendungspool häufig neu gestartet, vor allem bei hoher Auslastung (sofern festgelegt wurde, dass der Anwendungspool neu gestartet wird, sobald ein Arbeitsspeichergrenzwert erreicht wird)?
Der Grenzwert für den Arbeitsspeicher sollte zwischen 800 MB und 1,5 GB bei mindestens 2 GB RAM liegen. Wird der Neustart des Anwendungspools bei einem Wert ausgeführt, der nahe an 1 GB liegt, hat dies die besten Ergebnisse zur Folge. Sie können durch Ausprobieren herausfinden, welche Einstellungen für Ihre Umgebung am besten geeignet sind. Wenn die Einstellung für den Neustart zu niedrig ist, bringt dies Leistungsprobleme für Ihr System aufgrund von Seitenaustausch, der Fragmentierung des Arbeitsspeichers und anderen Faktoren mit sich.
Ist die Leistung des Systems vor allem bei starker Auslastung unzureichend?
Bei steigender Nutzung des Arbeitsspeichers muss das System kompensieren, z. B. durch Auslagern des Arbeitsspeichers und Durchführen von Arbeitsspeicherfragmentierungen.
Stürzt Ihr System ab oder treten vor allem bei hoher Auslastung unerwartete Fehler für Benutzer auf, wie z. B. Timeouts oder nicht verfügbare Seiten?
Wie bereits erwähnt, treten bei zunehmender Arbeitsspeicherauslastung oder -fragmentierung Fehler auf, da einige Funktionen keinen Arbeitsspeicher für andere Vorgänge zuweisen können. Häufig wird eine Ausnahme im Zusammenhang mit nicht genügend Arbeitsspeicher von Code nicht richtig verarbeitet und führt zu falschen oder irreführenden Fehlern.
Werden benutzerdefinierte Webparts, Drittanbieterwebparts oder benutzerdefinierte Anwendungen in Ihrem System verwendet?
Sie wissen möglicherweise nicht, dass diese Webparts SharePoint-Objekte verwerfen müssen und warum dies notwendig ist. Sie gehen davon aus, dass diese Funktion automatisch von der Garbage Collection durchgeführt wird. Allerdings ist dies nicht immer der Fall.
Wenn Sie Frage 4 und eine oder mehrere der anderen Fragen mit "ja" beantworten, ist die Wahrscheinlichkeit hoch, dass Elemente von Ihrem benutzerdefinierten Code nicht korrekt verworfen werden.
Wenn auf Ihren Websites eine der zuvor beschriebenen ungewöhnlichen Verhaltensweisen auftritt, können Sie feststellen, ob die Ursache ein Speicherverlust aufgrund von nicht ordnungsgemäß verworfenen Objekten ist, indem Sie die ULS-Protokolle (verfügbar unter C:\Program Files\Common Files\microsoft shared\Web Server Extensions\14\LOGS) nach Einträgen im Zusammenhang mit dem SPRequest-Objekt überprüfen. Jede Instanz von SPSite und SPWeb enthält einen Verweis auf ein SPRequest-Objekt, das wiederum einen Verweis auf ein nicht verwaltetes COM-Objekt enthält, das für die Kommunikation mit dem Datenbankserver sorgt. Die Anzahl der SPRequest-Objekte in einem bestimmten Thread und in parallelen Threads wird von SharePoint Foundation überwacht und den Protokollen in den folgenden drei Szenarien nützliche Einträge hinzugefügt:
Die Gesamtzahl der SPRequest-Objekte überschreitet einen konfigurierbaren Schwellenwert.
Ein SPRequest-Objekt ist am Ende eines Threads noch immer vorhanden.
Ein SPRequest-Objekt wurde durch die Garbage Collection aus dem Heap entfernt.
Das erste Szenario tritt am häufigsten auf, insbesondere wenn der Standardschwellenwert von acht SPRequest-Objekten für Ihre Website verwendet wird. Wenn die Anzahl der SPRequest-Objekte diesen Schwellenwert erreicht, wird der folgende Eintrag in den ULS-Protokollen angezeigt:
"Potentially excessive number of SPRequest objects (Anzahl der Objekte) currently unreleased on thread Threadnummer. Ensure that this object or its parent (such as an SPWeb or SPSite object) is being properly disposed. Allocation Id for this object: {GUID}"
Der optimale Schwellenwert variiert, abhängig von der Art Ihrer Website und der darin ausgeführten Anwendungen. Wenn Leistungsprobleme in Ihren Websites auftreten, sollten Sie die ULS-Protokolle Ihrer Installation überprüfen, um die Anzahl der von den Websiteanwendungen erstellten SPRequest-Objekte zu kennen. Auf diese Weise können Sie feststellen, ob zu viele SPRequest-Objekte durch Ihre Website- und Anwendungsentwürfe erstellt werden. Selbst wenn unzureichendes Verwerfen von Objekten nicht die Ursache Ihres Leistungsproblems ist, müssen Sie die Websites oder benutzerdefinierten Websiteanwendungen möglicherweise neu entwerfen, um die gesamte Arbeitsspeicherbelegung aufgrund der übermäßigen Verbreitung von SPRequest-Objekten zu reduzieren.
Da der sehr niedrige Standardschwellenwert möglicherweise nicht auf viele Websites anwendbar ist, können Sie den Wert durch Bearbeiten des folgenden Unterschlüssels der Registrierung ändern:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings
LocalSPRequestWarnCount = gewünschter Schwellenwert
Wenn Sie feststellen, dass SPRequest-Objekte aufgrund von unzureichendem Verwerfen von Objekten stark zunehmen und den Speicherbedarf Ihrer Websites unnötig ansteigen lässt, können Sie die jeweiligen Instanzen für das unzureichende Verwerfen ermitteln, indem Sie nach den folgenden zwei Einträgen suchen. Beide Meldungen verweisen auf Fälle, in denen Arbeitsspeicher aufgrund des unzureichenden Verwerfens von SharePoint-Objekten verschwendet wird, und hängen mit der Anzahl und dem Zustand von SPRequest-Objekten eines einzelnen Threads zusammen:
"An SPRequest object was not disposed before the end of this thread. To avoid wasting system resources, dispose 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 subkey 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."
Diese Meldung weist darauf hin, dass ein SPRequest-Objekt verworfen wurde, da es am Ende eines Threads noch vorhanden war.
"An SPRequest object was reclaimed by the garbage collector instead of being explicitly freed. To avoid wasting system resources, dispose 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."
Diese Meldung weist darauf hin, dass ein SPRequest-Objekt vom Garbage Collector verworfen wurde.
Zur Erkennung von Code, der das Problem verursacht, können Sie in den Protokollen nach Einträgen suchen, die die Zuordnungsbezeichner enthalten, oder den Anweisungen in den Warnungen folgen und die folgende Unterschlüsseleinstellung der Registrierung hinzufügen:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings SPRequestStackTrace = 1
Durch diese Unterschlüsseleinstellung wird sichergestellt, dass die Stapelüberwachung der ursprünglichen SPRequest-Zuweisung (tritt auf, wenn ein SPSite-Objekt oder ein SPWeb-Objekt erstellt wird) den Protokollen hinzugefügt wird, wenn diese Warnungen ausgegeben werden.
In den folgenden Abschnitten werden verschiedene Codiertechniken beschrieben, durch die Sie sicherstellen können, dass die Objekte ordnungsgemäß verworfen werden.
Codiertechniken für das ordnungsgemäße Verwerfen von Objekten
Sie können mithilfe bestimmter Codiertechniken sicherstellen, dass Objekte verworfen werden. Für diese Techniken müssen Sie in Ihrem Code Folgendes verwenden:
Die Dispose-Methode
Die using-Anweisung
Die Blöcke try, catch und finally
Verwenden der Dispose-Methode im Gegensatz zur . Close-Methode
Die Methoden Dispose und Close für die Objekte SPWeb und SPSite werden auf dieselbe Weise ausgeführt. Bei der Dispose-Methode wird die Close-Methode des Objekts aufgerufen. Es wird empfohlen, die Dispose-Methode anstelle der Close-Methode aufzurufen, da die Objekte SPWeb und SPSite die IDisposable-Schnittstelle implementieren und bei der standardmäßigen Garbage Collection in .NET Framework die Dispose-Methode aufgerufen wird, um dem Objekt zugeordnete Ressourcen aus dem Arbeitsspeicher freizugeben.
Die using-Anweisung
Sie können automatisch mithilfe der using-Anweisung von Microsoft Visual C# und Visual Basic SharePoint-Objekte verwerfen, die die IDisposable-Schnittstelle implementieren.
Der folgende Code enthält ein Beispiel.
String str;
using(SPSite oSPsite = new SPSite("https://server"))
{
using(SPWeb oSPWeb = oSPSite.OpenWeb())
{
str = oSPWeb.Title;
str = oSPWeb.Url;
}
}
Dim str As String
Using oSPsite As New SPSite("https://server")
Using oSPWeb As SPWeb = oSPSite.OpenWeb()
str = oSPWeb.Title
str = oSPWeb.Url
End Using
End Using
Durch die Nutzung von using-Anweisungen können Sie Ihren Code deutlich vereinfachen. Wie in der C#-Referenz vermerkt (using-Anweisung) werden using-Anweisungen von der(Common Language Runtime in try and finally-Blöcke übersetzt und alle Objekte, die die IDisposable-Schnittstelle implementieren, verworfen. In manchen Fällen ist die Verwendung von using-Anweisungen nicht empfehlenswert oder darf nur unter Vorbehalt und Berücksichtigung der Common Language Runtime verwendet werden. Das folgende Codebeispiel enthält einen Fall, in dem es nicht sinnvoll ist, dass die Common Language Runtime einen finally-Block erstellt und Objekte für Sie verwirft. In diesem Fall wird ein SPWeb-Objekt von SPContext zurückgegeben.
// Do not do this. Dispose() is automatically called on SPWeb.
using( SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) { ... }
' Do not do this. Dispose() is automatically called on SPWeb.
Using web As SPWeb = SPControl.GetContextWeb(HttpContext.Current)
'.......
End Using
SPContext-Objekte werden vom SharePoint-Framework verwaltet und sollten nicht explizit in Ihrem Code verworfen werden. Dies gilt auch für die Objekte SPSite und SPWeb, die von SPContext.Site, SPContext.Current.Site, SPContext.Web und SPContext.Current.Web zurückgegeben werden.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_220" identifizierte Problem beschrieben. |
Gehen Sie unter Vorbehalt und unter Berücksichtigung der Aktionen der Common Language Runtime vor, wenn Sie Aufrufe des SharePoint-Objektmodells auf derselben Zeile kombinieren. Speicherverluste im Zusammenhang mit einem solchen Szenario sind äußerst schwer aufzufinden.
Im folgenden Codebeispiel wird ein SPSite-Objekt instanziiert, jedoch nicht verworfen, da die Common Language Runtime sicherstellt, dass nur das von OpenWeb zurückgegebene SPWeb-Objekt verworfen wird.
void CombiningCallsLeak()
{
using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
{
// ... New SPSite will be leaked.
} // SPWeb object web.Dispose() automatically called.
}
Private Sub CombiningCallsLeak()
Using web As SPWeb = New SPSite(SPContext.Current.Web.Url).OpenWeb()
' ... New SPSite will be leaked.
End Using ' SPWeb object web.Dispose() automatically called.
End Sub
Sie können dieses Problem beheben, indem Sie eine using-Anweisung in einer anderen schachteln.
void CombiningCallsBestPractice()
{
using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Perform operations on site.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub CombiningCallsBestPractice()
Using siteCollection As New SPSite(SPContext.Current.Web.Url)
Using web As SPWeb = siteCollection.OpenWeb()
' Perform operations on site.
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Wenn keine Vorgänge für das SPSite-Objekt durchgeführt werden sollen, können Sie dies wie im folgenden Codebeispiel veranschaulicht prägnanter schreiben.
void CombiningCallsBestPractice()
{
using (SPSite siteCollection = new SPSite(SPContext.Current.Web.Url))
using (SPWeb web = siteCollection.OpenWeb())
{
// Perform operations on site.
} // SPWeb object web.Dispose() automatically called; SPSite object
// siteCollection.Dispose() automatically called.
}
Private Sub CombiningCallsBestPractice()
Using siteCollection As New SPSite(SPContext.Current.Web.Url)
Using web As SPWeb = siteCollection.OpenWeb()
' Perform operations on site.
End Using ' SPWeb object web.Dispose() automatically called; SPSite object
End Using
' siteCollection.Dispose() automatically called.
End Sub
Andernfalls müssen Sie eigene try-, catch- und finally-Blöcke erstellen. Offensichtliche Beispiele sind Szenarien, in denen Sie Ausnahmen behandeln und daher einen catch-Block einschließen müssen. Der folgende Abschnitt enthält Richtlinien für den richtigen Zeitpunkt und die richtige Art der Verwendung von try-, catch- und finally-Blöcken.
Die Blöcke "try", "catch" und "finally"
Die Verwendung von try-, catch- und finally-Blöcken ist offensichtlich immer dann sinnvoll, wenn Ausnahmen behandelt werden müssen. Der Code in einem try/catch-Block sollte einer finally-Klausel unterliegen, durch die sichergestellt ist, dass Objekte, die IDisposable implementieren, verworfen werden. Im folgenden Codebeispiel wollten Sie den catch-Block mit Code füllen, der für die Ausnahmebehandlung sorgt. Ein catch-Block sollte niemals leer bleiben. Beachten Sie auch die bewährte Methode, vor dem Verwerfen zu testen, ob null vorhanden ist.
String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("https://server");
oSPWeb = oSPSite.OpenWeb(..);
str = oSPWeb.Title;
}
catch(Exception e)
{
// Handle exception, log exception, etc.
}
finally
{
if (oSPWeb != null)
oSPWeb.Dispose();
if (oSPSite != null)
oSPSite.Dispose();
}
Dim str As String
Dim oSPSite As SPSite = Nothing
Dim oSPWeb As SPWeb = Nothing
Try
oSPSite = New SPSite("https://server")
oSPWeb = oSPSite.OpenWeb(..)
str = oSPWeb.Title
Catch e As Exception
' Handle exception, log exception, etc.
Finally
If oSPWeb IsNot Nothing Then
oSPWeb.Dispose()
End If
If oSPSite IsNot Nothing Then
oSPSite.Dispose()
End If
End Try
Wie im folgenden Codebeispiel veranschaulicht, sind die Blöcke Try und finally oder eine using-Anweisung erforderlich, um mögliche Speicherverluste zu vermeiden, wenn Sie ein verwerfbares Objekt in einem foreach-Block erstellen.
public static void SPSiteCollectionForEachBestPractice()
{
string sUrl = "http://spvm";
using (SPSite siteCollectionOuter = new SPSite(sUrl))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollectionInner = null;
foreach (siteCollectionInner in siteCollections)
{
try // Should be first statement after foreach.
{
Console.WriteLine(siteCollectionInner.Url);
// Exception occurs here.
}
finally
{
if(siteCollectionInner != null)
siteCollectionInner.Dispose();
}
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Public Shared Sub SPSiteCollectionForEachBestPractice()
Dim sUrl As String = "http://spvm"
Using siteCollectionOuter As New SPSite(sUrl)
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Dim siteCollectionInner As SPSite = Nothing
For Each siteCollectionInner In siteCollections
Try ' Should be first statement after foreach.
Console.WriteLine(siteCollectionInner.Url)
' Exception occurs here.
Finally
If siteCollectionInner IsNot Nothing Then
siteCollectionInner.Dispose()
End If
End Try
Next
End Using
End Sub ' SPSite object siteCollectionOuter.Dispose() automatically called.
"Response.Redirect" mit try-, catch- und finally-Blöcken sowie using-Anweisungen
Der finally-Block wird nach Aufrufen von Response.Redirect im try-Block ausgeführt. Response.Redirect generiert letztlich eine ThreadAbortException-Ausnahme. Wenn diese Ausnahme ausgelöst wird, führt die Common Language Runtime allefinally-Blöcke vor Beenden des Threads aus. Da der finally-Block jedoch eine unbegrenzte Berechnung durchführen oder die Ausführung von ThreadAbortException abbrechen kann, wird der Thread nicht notwendigerweise beendet. Vor dem Umleiten oder Übertragen der Verarbeitung müssen Sie daher die Objekte verwerfen. Ist eine Umleitung im Code notwendig, implementieren Sie diese wie im folgenden Codebeispiel veranschaulicht.
String str;
SPSite oSPSite = null;
SPWeb oSPWeb = null;
try
{
oSPSite = new SPSite("https://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();
}
Dim str As String
Dim oSPSite As SPSite = Nothing
Dim oSPWeb As SPWeb = Nothing
Try
oSPSite = New SPSite("https://server")
oSPWeb = oSPSite.OpenWeb(..)
str = oSPWeb.Title
If bDoRedirection Then
If oSPWeb IsNot Nothing Then
oSPWeb.Dispose()
End If
If oSPSite IsNot Nothing Then
oSPSite.Dispose()
End If
Response.Redirect("newpage.aspx")
End If
Catch e As Exception
Finally
If oSPWeb IsNot Nothing Then
oSPWeb.Dispose()
End If
If oSPSite IsNot Nothing Then
oSPSite.Dispose()
End If
End Try
Da die Common Language Runtime von einer using-Anweisung angewiesen wird, einen finally-Block zu erstellen, sollten Sie bei Verwendung von Response.Redirect innerhalb einer using-Anweisung sicherstellen, dass Objekte ordnungsgemäß verworfen werden. Dies wird im folgenden Codebeispiel veranschaulicht.
using (SPSite oSPSite = new SPSite("https://server"))
using (SPWeb oSPWeb = oSPSite.OpenWeb(..))
{
if (bDoRedirection)
Response.Redirect("newpage.aspx");
}
Using oSPSite As New SPSite("https://server")
Using oSPWeb As SPWeb = oSPSite.OpenWeb(..)
If bDoRedirection Then
Response.Redirect("newpage.aspx")
End If
End Using
End Using
Empfehlungen zur Reduzierung der langfristigen Aufbewahrung von Objekten
Sie können die langfristige Aufbewahrung von SharePoint-Objekten reduzieren, indem Sie diesen allgemeinen Empfehlungen folgen.
Wenn Sie das Objekt mithilfe eines new-Operators erstellen, stellen Sie sicher, dass die erstellende Anwendung diesen verwirft.
Hinweis In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_110" identifizierte Problem beschrieben.
Beispiel 1 für guten Code
Explizites Verwerfen
void CreatingSPSiteExplicitDisposeNoLeak() { SPSite siteCollection = null; try { siteCollection = new SPSite("http://moss"); } finally { if (siteCollection != null) siteCollection.Dispose(); } }
Private Sub CreatingSPSiteExplicitDisposeNoLeak() Dim siteCollection As SPSite = Nothing Try siteCollection = New SPSite("http://moss") Finally If siteCollection IsNot Nothing Then siteCollection.Dispose() End If End Try End Sub
Beispiel 2 für guten Code
Automatisches Verwerfen
CreatingSPSiteWithAutomaticDisposeNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { } // SPSite object siteCollection.Dispose() is called automatically. }
CreatingSPSiteWithAutomaticDisposeNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { } // SPSite object siteCollection.Dispose() is called automatically. }
Verwerfen Sie durch SharePoint-Methoden erstellte Elemente, die andere SPWeb-Objekte zurückgeben (z. B. OpenWeb()).
Hinweis In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_120" identifizierte Problem beschrieben.
Beispiel für guten Code
void OpenWebNoLeak() { using (SPSite siteCollection = new SPSite("http://moss")) { using (SPWeb web = siteCollection.OpenWeb()) { } // SPWeb object web.Dispose() automatically called. } // SPSite object siteCollection.Dispose() automatically called. }
Private Sub OpenWebNoLeak() Using siteCollection As New SPSite("http://moss") Using web As SPWeb = siteCollection.OpenWeb() End Using ' SPWeb object web.Dispose() automatically called. End Using ' SPSite object siteCollection.Dispose() automatically called. End Sub
Geben Sie kein SPRequest-Objekt (und erweiternd kein Objekt, das einen Verweis auf ein SPRequest-Objekt enthält) threadübergreifend frei. Codiertechniken, bei denen ein SPRequest-Objekt zwischen zwei oder mehr Threads freigegeben wird oder ein SPRequest-Objekt in einem Thread erstellt und in einem anderen verworfen wird, werden nicht unterstützt. Somit können Sie keine Objekte mit einem Verweis auf ein SPRequest-Objekt in einer statischen Variablen speichern. Speichern Sie deshalb keine SharePoint-Objekte, die IDisposable implementieren (wie z. B. SPWeb oder SPSite) in statischen Variablen.
SPSite-Objekte
In diesem Abschnitt werden Situationen beschrieben, in denen neue SPSite-Objekte zurückgegeben und verworfen werden müssen.
Im Allgemeinen sollte eine aufrufende Anwendung jedes Mal, wenn die neuen SPSite-Konstruktoren (eine Signatur) verwendet werden, nach der Verwendung des Objekts die Dispose()-Methode aufrufen. Wenn das SPSite-Objekt von GetContextSite() stammt, sollte die aufrufende Anwendung das Objekt nicht verwerfen. Da die Objekte SPWeb und SPSite eine interne Liste führen, die auf diese Weise abgeleitet wird, kann das Verwerfen des Objekts zu unvorhersehbaren Verhaltensweisen des SharePoint-Objektmodells führen. Intern durchläuft SharePoint Foundation diese Liste nach dem Beenden der Seite aus, um die Objekte ordnungsgemäß zu verwerfen.
SPSiteCollection-Klasse
In diesem Abschnitt werden die Methoden, Eigenschaften oder Operatoren im SPSiteCollection-Objekt beschrieben, die erfordern, dass das zurückgegebene SPSite-Objekt nach dem Zugreifen geschlossen wird.
SPSiteCollection.Add-Methode
Durch die SPSiteCollection.Add-Methode wird ein neues SPSite-Objekt erstellt und zurückgegeben. Verwerfen Sie alle SPSite-Objekte, die von der SPSiteCollection.Add-Methode zurückgegeben werden.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_240" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void SPSiteCollectionAddLeak()
{
SPWebApplication webApp = new SPSite("http://moss").WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
"roger.lamb@litwareinc.com");
// SPSite siteCollection leak.
}
Private Sub SPSiteCollectionAddLeak()
Dim webApp As SPWebApplication = New SPSite("http://moss").WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Dim siteCollection As SPSite = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\User", "roger.lamb@litwareinc.com")
' SPSite siteCollection leak.
End Sub
Beispiel für guten Code
void SPSiteCollectionAddNoLeak()
{
SPWebApplication webApp = new SPSite("http://moss").WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
using (SPSite siteCollection = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\\User",
"roger.lamb@litwareinc.com"))
{
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPSiteCollectionAddNoLeak()
Dim webApp As SPWebApplication = New SPSite("http://moss").WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Using siteCollection As SPSite = siteCollections.Add("sites/myNewSiteCollection", "DOMAIN\User", "roger.lamb@litwareinc.com")
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
SPSiteCollection [ ]-Indexoperator
Bei jedem Zugriff wird ein neues SPSite-Objekt vom SPSiteCollection []-Indexoperator zurückgegeben. Es wird eine SPSite-Instanz erstellt, selbst wenn bereits auf das Objekt zugegriffen worden ist. In den folgenden Codebeispielen wird veranschaulicht, wie das SPSite-Objekt nicht ordnungsgemäß verworfen wird.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_230" identifizierte Problem beschrieben. |
Beispiel 1 für schlechten Code
Verwenden des Indexoperators
void SPSiteCollectionIndexerLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://moss"))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
SPSite siteCollectionInner = siteCollections[0];
// SPSite siteCollectionInner leak.
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionIndexerLeak()
Using siteCollectionOuter As New SPSite("http://moss")
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
Dim siteCollectionInner As SPSite = siteCollections(0)
' SPSite siteCollectionInner leak.
End Using ' SPSite object siteCollectionOuter.Dispose() automatically called.
End Sub
Beispiel 2 für schlechten Code
Verwenden der foreach-Schleife
void SPSiteCollectionForEachLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://moss"))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
foreach (SPSite siteCollectionInner in siteCollections)
{
// SPSite siteCollectionInner leak.
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionForEachLeak()
Using siteCollectionOuter As New SPSite("http://moss")
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
For Each siteCollectionInner As SPSite In siteCollections
' SPSite siteCollectionInner leak.
Next siteCollectionInner
End Using ' SPSite object siteCollectionOuter.Dispose() automatically called.
End Sub
Beispiel 1 für guten Code
Verwenden des Indexoperators
void SPSiteCollectionIndexerNoLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://moss"))
{
SPSite siteCollectionInner = null;
try
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
siteCollectionInner = siteCollections[0];
}
finally
{
if (siteCollectionInner != null)
siteCollectionInner.Dispose();
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionIndexerNoLeak()
Using siteCollectionOuter As New SPSite("http://moss")
Dim siteCollectionInner As SPSite = Nothing
Try
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
siteCollectionInner = siteCollections(0)
Finally
If siteCollectionInner IsNot Nothing Then
siteCollectionInner.Dispose()
End If
End Try
End Using ' SPSite object siteCollectionOuter.Dispose() automatically called.
End Sub
Beispiel 2 für guten Code
Verwenden der foreach-Schleife
void SPSiteCollectionForEachNoLeak()
{
using (SPSite siteCollectionOuter = new SPSite("http://yoursite”))
{
SPWebApplication webApp = siteCollectionOuter.WebApplication;
SPSiteCollection siteCollections = webApp.Sites;
foreach (SPSite siteCollectionInner in siteCollections)
{
try
{
// ...
}
finally
{
if(siteCollectionInner != null)
siteCollectionInner.Dispose();
}
}
} // SPSite object siteCollectionOuter.Dispose() automatically called.
}
Private Sub SPSiteCollectionForEachNoLeak()
Using siteCollectionOuter As SPSite = New SPSite("http://yoursite")
Dim webApp As SPWebApplication = siteCollectionOuter.WebApplication
Dim siteCollections As SPSiteCollection = webApp.Sites
For Each siteCollectionInner As SPSite In siteCollections
Try
' ...
Finally
If siteCollectionInner IsNot Nothing Then
siteCollectionInner.Dispose()
End If
End Try
Next
End Using
End Sub
SPSite.AllWebs-Eigenschaft ("SPWebCollection")
In diesem Abschnitt werden die Methoden, Eigenschaften oder Operatoren in der AllWebs-Eigenschaftensammlung beschrieben, die erfordern, dass das SPWeb-Objekt nach dem Zugreifen geschlossen wird.
SPSite.AllWebs.Add-Methode
Durch die SPSite.AllWebs.Add-Methode wird ein SPWeb-Objekt erstellt und zurückgegeben. Verwerfen Sie alle SPWeb-Objekte, die von SPSite.AllWebs.Add zurückgegeben werden.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_150" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void AllWebsAddLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
SPWeb web = siteCollection.AllWebs.Add("site-relative URL");
// SPWeb object leaked.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsAddLeak()
Using siteCollection As New SPSite("http://moss")
Dim web As SPWeb = siteCollection.AllWebs.Add("site-relative URL")
' SPWeb object leaked.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void AllWebsAddNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.AllWebs.Add("site-relative URL"))
{
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsAddNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.AllWebs.Add("site-relative URL")
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
SPWebCollection.Add-Methode
Es wird ein SPWeb-Objekt von der SPWebCollection.Add-Methode erstellt und zurückgegeben, das verworfen werden muss.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_200" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void SPWebCollectionAddLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
SPWebCollection webCollection = siteCollection.AllWebs; // No AllWebs leak just getting reference.
SPWeb innerWeb = webCollection.Add(strWebUrl); // Must dispose innerWeb.
// innerWeb leak.
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPWebCollectionAddLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
Dim webCollection As SPWebCollection = siteCollection.AllWebs ' No AllWebs leak just getting reference.
Dim innerWeb As SPWeb = webCollection.Add(strWebUrl) ' Must dispose innerWeb.
' innerWeb leak.
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void SPWebCollectionAddNoLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
SPWebCollection webCollection = siteCollection.AllWebs; // No AllWebs leak just getting reference.
using (SPWeb innerWeb = webCollection.Add(strWebUrl))
{
//...
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPWebCollectionAddNoLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
Dim webCollection As SPWebCollection = siteCollection.AllWebs ' No AllWebs leak just getting reference.
Using innerWeb As SPWeb = webCollection.Add(strWebUrl)
'...
End Using
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
SPSite.AllWebs [ ]-Indexoperator
Vom SPSite.AllWebs []-Indexoperator wird bei jedem Zugriff eine neue SPWeb-Instanz zurückgegeben. Während der Indizierung wird ein Objekt erstellt, selbst wenn bereits auf dieses Objekt zugegriffen worden ist. Sofern es nicht explizit geschlossen wird, bleibt in den folgenden Codebeispielen ein SPWeb-Objekt im Garbage Collector von .NET Framework zurück.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_130" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void AllWebsForEachLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in siteCollection.AllWebs)
{
// Explicitly dispose here to avoid out of memory leaks with large number of SPWeb objects.
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsForEachLeak()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In siteCollection.AllWebs
' Explicitly dispose here to avoid out of memory leaks with large number of SPWeb objects.
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel 1 für guten Code
Verwenden der foreach-Schleife
void AllWebsForEachNoLeakOrMemoryOOM()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in siteCollection.AllWebs)
{
try
{
// ...
}
finally
{
if(innerWeb != null)
innerWeb.Dispose();
}
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsForEachNoLeakOrMemoryOOM()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In siteCollection.AllWebs
Try
' ...
Finally
If innerWeb IsNot Nothing Then
innerWeb.Dispose()
End If
End Try
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel 2 für guten Code
Verwenden des Indexoperators
void AllWebsIndexerNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.AllWebs[0])
{
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub AllWebsIndexerNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.AllWebs(0)
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Die Methoden "SPSite.OpenWeb" und "SPSite. SelfServiceCreateSite"
Über die OpenWeb()-Methode und die SelfServiceCreateSite-Methode (alle Signaturen) des SPSite-Objekts wird ein SPWeb-Objekt erstellt und an den Aufrufer zurückgegeben. Dieses neue Objekt wird nicht im SPSite-Objekt gespeichert und nicht in der SPSite-Klasse verworfen. Deshalb sollten Sie jedes Objekt verwerfen, das über eine dieser Methoden erstellt wurde.
Beispiel für schlechten Code
void OpenWebLeak()
{
using (SPWeb web = new SPSite(SPContext.Current.Web.Url).OpenWeb())
{
// SPSite leaked !
} // SPWeb object web.Dispose() automatically called.
}
Private Sub OpenWebLeak()
Using web As SPWeb = New SPSite(SPContext.Current.Web.Url).OpenWeb()
' SPSite leaked !
End Using ' SPWeb object web.Dispose() automatically called.
End Sub
Beispiel für guten Code
void OpenWebNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub OpenWebNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
SPSite.RootWeb-Eigenschaft
Bisher galt die Regel, dass die aufrufende Anwendung die SPSite.RootWeb-Eigenschaft direkt vor dem Verwerfen des SPSite-Objekts, das diese verwendet, verworfen werden sollte. Diese Regel ist nicht länger gültig. Die Bereinigung durch Verwerfen wird automatisch sowohl von SharePoint Foundation als auch von SharePoint Server ausgeführt. Darüber hinaus wurde die RootWeb-Eigenschaft intern von den SPSite-Eigenschaften LockIssue, Owner und SecondaryContact verwendet. Angesichts der neuen Regel für die Verwendung von RootWeb ist es nicht mehr sinnvoll, die Dispose-Methode für die SPSite.RootWeb-Eigenschaft aufzurufen, wenn eine dieser Eigenschaften verwendet wird.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_140" identifizierte Problem beschrieben. |
Beispiel für guten Code
public void RootWebBestPractice()
{
// New SPSite.
using (SPSite siteCollection = new SPSite("http://moss"))
{
SPWeb rootWeb1 = siteCollection.RootWeb;
// No explicit rootWeb1 dispose required.
} // siteCollection automatically disposed by implementing using().
// rootWeb1 will be Disposed by SPSite.
// SPContext and SPControl
SPWeb rootWeb2 = SPContext.Current.Site.RootWeb;
// Also would apply to SPControl.GetContextSite(Context);
// No explicit rootWeb2 dispose required because it is obtained from SPContext.Current.Site.
}
Public Sub RootWebBestPractice()
' New SPSite.
Using siteCollection As New SPSite("http://moss")
Dim rootWeb1 As SPWeb = siteCollection.RootWeb
' No explicit rootWeb1 dispose required.
End Using ' siteCollection automatically disposed by implementing using().
' rootWeb1 will be Disposed by SPSite.
' SPContext and SPControl
Dim rootWeb2 As SPWeb = SPContext.Current.Site.RootWeb
' Also would apply to SPControl.GetContextSite(Context);
' No explicit rootWeb2 dispose required because it is obtained from SPContext.Current.Site.
End Sub
Microsoft.Office.Server.UserProfiles.PersonalSite (nur Office SharePoint Server 2007)
Es wird ein SPSite-Objekt von Microsoft.Office.Server.UserProfiles.PersonalSite zurückgegeben, das verworfen werden muss.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_400" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void PersonalSiteLeak()
{
// Open a site collection.
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
SPSite personalSite = profile.PersonalSite; // Will leak.
}
}
Private Sub PersonalSiteLeak()
' Open a site collection.
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Dim personalSite As SPSite = profile.PersonalSite ' Will leak.
End Using
End Sub
Beispiel für guten Code
void PersonalSiteNoLeak()
{
// Open a site collection.
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
using (SPSite personalSite = profile.PersonalSite)
{
// ...
}
}
}
Private Sub PersonalSiteNoLeak()
' Open a site collection.
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Using personalSite As SPSite = profile.PersonalSite
' ...
End Using
End Using
End Sub
In einem anderen Grenzfall führt UserProfiles.PersonalSite, wie im folgenden Codebeispiel dargestellt, zu Speicherverlusten.
void PersonalSiteLeak()
{
// Open a site collection.
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
SPSite personalSite = profile.PersonalSite; // Will leak.
}
}
Private Sub PersonalSiteLeak()
' Open a site collection.
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Dim personalSite As SPSite = profile.PersonalSite ' Will leak.
End Using
End Sub
Sie können diese Art von Speicherverlusten umgehen, indem Sie das im folgenden Codebeispiel dargestellte Muster einhalten.
void PersonalSiteNoLeak()
{
// Open a site collection
using (SPSite siteCollection = new SPSite("http://moss"))
{
UserProfileManager profileManager = new UserProfileManager(ServerContext.GetContext(siteCollection));
UserProfile profile = profileManager.GetUserProfile("domain\\username");
using (SPSite personalSite = profile.PersonalSite)
{
// ...
}
}
}
Private Sub PersonalSiteNoLeak()
' Open a site collection
Using siteCollection As New SPSite("http://moss")
Dim profileManager As New UserProfileManager(ServerContext.GetContext(siteCollection))
Dim profile As UserProfile = profileManager.GetUserProfile("domain\username")
Using personalSite As SPSite = profile.PersonalSite
' ...
End Using
End Using
End Sub
Wie im folgenden Beispiel dargestellt, können Sie durch Abrufen eines PersonalSite-Objekts aus ProfileLoader die Leistung steigern (und das Erstellen eines SPSite-Objekts vermeiden).
UserProfile myProfile = ProfileLoader.GetProfileLoader().GetUserProfile();
using (SPSite personalSite = myProfile.PersonalSite)
{
// ...
}
Dim myProfile As UserProfile = ProfileLoader.GetProfileLoader().GetUserProfile()
Using personalSite As SPSite = myProfile.PersonalSite
' ...
End Using
Wenn Sie ein Webpart für "Meine Website" erstellen, können Sie darüber hinaus eine Instanz von PersonalSite verwenden, die nicht verworfen werden muss.
IPersonalPage currentMySitePage = this.Page as IPersonalPage;
if (currentMySitePage != null && !currentMySitePage.IsProfileError)
{
SPSite personalSite = currentMySitePage.PersonalSite; // Will not leak.
// ...
}
Dim currentMySitePage As IPersonalPage = TryCast(Me.Page, IPersonalPage)
If currentMySitePage IsNot Nothing AndAlso (Not currentMySitePage.IsProfileError) Then
Dim personalSite As SPSite = currentMySitePage.PersonalSite ' Will not leak.
' ...
End If
SPWeb-Objekte
In diesem Abschnitt werden die Situationen beschrieben, in denen SPWeb-Objekte zurückgegeben und möglicherweise verworfen werden müssen.
SPWeb.ParentWeb-Eigenschaft
Aktualisierter Leitfaden
In früheren Leitfäden wurde empfohlen, dass SPWeb.ParentWeb. von der aufrufenden Anwendung verworfen werden sollte. Diese Regel ist nicht mehr gültig. Die Bereinigung durch Verwerfen wird automatisch sowohl von SharePoint Foundation als auch von SharePoint Server durchgeführt.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_170" identifizierte Problem beschrieben. |
Beispiel für guten Code
using (SPSite site = new SPSite("https://localhost"))
{
using (SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["Announcements"];
SPWeb parentWeb = list.ParentWeb; //No explicit dispose required.
}
}
Using site As New SPSite("https://localhost")
Using web As SPWeb = site.OpenWeb()
Dim list As SPList = web.Lists("Announcements")
Dim parentWeb As SPWeb = list.ParentWeb 'No explicit dispose required.
End Using
End Using
SPWeb.Webs-Eigenschaft
In diesem Abschnitt werden die Methoden, Eigenschaften oder Operatoren in der Webs-Eigenschaftensammlung beschrieben, die erfordern, dass das SPWeb-Objekt nach dem Zugreifen verworfen wird.
SPWeb.Webs
Es wird ein SPWebCollection-Objekt von der SPWeb.Webs-Eigenschaft zurückgegeben. Die SPWeb-Objekte in dieser Sammlung müssen verworfen werden.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_180" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void WebsLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in outerWeb.Webs)
{
// SPWeb innerWeb leak.
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsLeak()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In outerWeb.Webs
' SPWeb innerWeb leak.
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void WebsNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb outerWeb = siteCollection.OpenWeb())
{
foreach (SPWeb innerWeb in outerWeb.Webs)
{
try // Should be first statement after foreach.
{
// ...
}
finally
{
if(innerWeb != null)
innerWeb.Dispose();
}
}
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsNoLeak()
Using siteCollection As New SPSite("http://moss")
Using outerWeb As SPWeb = siteCollection.OpenWeb()
For Each innerWeb As SPWeb In outerWeb.Webs
Try ' Should be first statement after foreach.
' ...
Finally
If innerWeb IsNot Nothing Then
innerWeb.Dispose()
End If
End Try
Next
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
SPWeb.Webs.Add
Durch die SPWeb.Webs.Add-Methode (oder SPWebCollection.Add) wird ein neues SPWeb-Objekt erstellt und zurückgegeben. Sie sollten alle SPWeb-Objekte verwerfen, die durch Aufrufen dieser Methode zurückgegeben werden.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_190" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void WebsAddLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
SPWeb addedWeb = web.Webs.Add(strWebUrl); // Will leak.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsAddLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim addedWeb As SPWeb = web.Webs.Add(strWebUrl) ' Will leak.
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void WebsAddNoLeak(string strWebUrl)
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
using (SPWeb addedWeb = web.Webs.Add(strWebUrl))
{
//..
}
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub WebsAddNoLeak(ByVal strWebUrl As String)
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Using addedWeb As SPWeb = web.Webs.Add(strWebUrl)
'..
End Using
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
SPWeb.Webs[]-Indexoperator
Bei jedem Zugriff wird ein neues SPWeb-Objekt vom SPWeb.Webs[]-Indexoperator zurückgegeben. Durch Aufrufen der OpenWeb-Methode wird ein SPWeb-Objekt erstellt, selbst wenn bereits auf dieses Objekt zugegriffen worden ist. In den folgenden Codebeispielen wird die langfristige Aufbewahrung dieser Objekte im Arbeitsspeicher, wie in .NET Framework der Fall, veranschaulicht.
Beispiel 1 für schlechten Code
Verwenden der For-Schleife
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);
}
Dim i As Integer
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For i = 0 To oSPWeb.Webs.Count - 1
oSPWeb2 = oSPWeb.Webs(i)
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
Next i
Beispiel 2 für schlechten Code
Verwenden der foreach-Schleife
SPWeb oSPWeb, oSPWeb2;
SPSite oSPSite = SPControl.GetContextSite(Context);
oSPWeb = oSPSite.OpenWeb();
foreach(SPWeb oSPWeb2 in oSPWebe.Webs)
{
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title);
}
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For Each oSPWeb2 As SPWeb In oSPWebe.Webs
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
Next
Durch Verwerfen am Ende jeder einzelnen Schleife kann das Problem behoben werden.
Beispiel 1 für guten Code
Verwenden der For-Schleife
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();
Dim i As Integer
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For i = 0 To oSPWeb.Webs.Count - 1
oSPWeb2 = oSPWeb.Webs(i)
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
oSPWeb2.Dispose()
Next i
oSPWeb.Dispose()
Beispiel 2 für guten Code
Verwenden der foreach-Schleife
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();
Dim oSPWeb, oSPWeb2 As SPWeb
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
oSPWeb = oSPSite.OpenWeb()
For Each oSPWeb2 As SPWeb In oSPWeb.Webs
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
oSPWeb2.Dispose()
Next
oSPWeb.Dispose()
Beispiel 3 für guten Code
Verwenden der for-Schleife mit automatischem Verwerfen
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);
}
}
}
Dim i As Integer
Dim oSPSite As SPSite = SPControl.GetContextSite(Context)
Using oSPWeb As SPWeb = oSPSite.OpenWeb()
For i = 0 To oSPWeb.Webs.Count - 1
Using oSPWeb2 As SPWeb = oSPWeb.Webs(i)
BuildTableRow(oDisplayTable, "Web", oSPWeb2.Title)
End Using
Next
End Using
Sonstige Objekte, die verworfen werden müssen
In diesem Abschnitt wird das Aufrufen der Dispose-Methode für andere SharePoint-Objekte beschrieben.
Microsoft.SharePoint.Portal.SiteData.Area.Web-Eigenschaft
Bei jedem Zugreifen wird ein neues SPWeb-Objekt von der Web-Eigenschaft der SharePoint.Portal.SiteData.Area-Klasse zurückgegeben. Bei Verwendung der Area.Web-Eigenschaft sollte entsprechend die Dispose-Methode aufgerufen werden. Obwohl die Klassen Area und AreaManager mittlerweile veraltet sind, muss dies beim Migrieren von Code aus Vorversionen beachtet werden.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_500" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void AreaWebLeak()
{
// AreaManager and Area are obsolete in SharePoint Server, but this
// should still be noted.
Area area = AreaManager.GetArea(PortalContext.Current, new Guid("{GUID}"));
string str = area.Web.Title;
// SPWeb area.Web leak.
}
Private Sub AreaWebLeak()
' AreaManager and Area are obsolete in SharePoint Server, but this
' should still be noted.
Dim area As Area = AreaManager.GetArea(PortalContext.Current, New Guid("{GUID}"))
Dim str As String = area.Web.Title
' SPWeb area.Web leak.
End Sub
Beispiel für guten Code
public void AreaWebNoLeak()
{
// AreaManager and Area are obsolete but this should still be noted.
Area area = AreaManager.GetArea(PortalContext.Current, new Guid("{GUID}"));
using (SPWeb areaWeb = area.Web)
{
string str = areaWeb.Title;
}
}
Public Sub AreaWebNoLeak()
' AreaManager and Area are obsolete but this should still be noted.
Dim area As Area = AreaManager.GetArea(PortalContext.Current, New Guid("{GUID}"))
Using areaWeb As SPWeb = area.Web
Dim str As String = areaWeb.Title
End Using
End Sub
Die Methoden "SPControl.GetContextSite" und "SPControl.GetContextWeb"
Wenn das Objekt von den SharePoint-Kontextobjekten stammt (die Methoden GetContextSite und GetContextWeb in der SPControl-Klasse), sollte die Dispose-Methode nicht von der aufrufenden Anwendung für das Objekt aufgerufen werden. Dies kann zu unvorhersehbaren Verhaltensweisen oder zu Fehlern des SharePoint-Objektmodells führen. Grund dafür ist eine interne Liste in den Objekten SPSite und SPWeb, die auf diese Weise abgeleitet wird. Intern durchläuft das Objektmodell diese Liste nach dem Beenden der Seite, um die Objekte ordnungsgemäß zu verwerfen.
Ein Objekt, das über diese Objekte erstellt wird, sollte weiterhin verworfen werden, wie z. B. beim Öffnen einer Website über ein SPSite-Objekt, das Sie mithilfe der GetContextSite-Methode abgerufen haben.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_210" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void SPControlBADPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
siteCollection.Dispose(); // DO NOT DO THIS.
SPWeb web = SPControl.GetContextWeb(Context);
web.Dispose(); // DO NOT DO THIS.
}
Private Sub SPControlBADPractice()
Dim siteCollection As SPSite = SPControl.GetContextSite(Context)
siteCollection.Dispose() ' DO NOT DO THIS.
Dim web As SPWeb = SPControl.GetContextWeb(Context)
web.Dispose() ' DO NOT DO THIS.
End Sub
Beispiel für guten Code
void SPControlBestPractice()
{
SPSite siteCollection = SPControl.GetContextSite(Context);
SPWeb web = SPControl.GetContextWeb(Context);
// Do NOT call Dispose().
}
Private Sub SPControlBestPractice()
Dim siteCollection As SPSite = SPControl.GetContextSite(Context)
Dim web As SPWeb = SPControl.GetContextWeb(Context)
' Do NOT call Dispose().
End Sub
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager
Die SPLimitedWebPartManager-Klasse enthält einen Verweis auf ein internes SPWeb-Objekt, das verworfen werden muss.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_160" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void SPLimitedWebPartManagerLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
SPFile page = web.GetFile("Source_Folder_Name/Source_Page");
SPLimitedWebPartManager webPartManager =
page.GetLimitedWebPartManager(PersonalizationScope.Shared);
// SPWeb object webPartManager.Web leaked.
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPLimitedWebPartManagerLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim page As SPFile = web.GetFile("Source_Folder_Name/Source_Page")
Dim webPartManager As SPLimitedWebPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared)
' SPWeb object webPartManager.Web leaked.
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void SPLimitedWebPartManagerLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
SPFile page = web.GetFile("Source_Folder_Name/Source_Page");
SPLimitedWebPartManager webPartManager =
page.GetLimitedWebPartManager(PersonalizationScope.Shared);
webPartManaber.Web.Dispose();
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub SPLimitedWebPartManagerLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim page As SPFile = web.GetFile("Source_Folder_Name/Source_Page")
Dim webPartManager As SPLimitedWebPartManager = page.GetLimitedWebPartManager(PersonalizationScope.Shared)
webPartManaber.Web.Dispose()
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Microsoft.SharePoint.Publishing.PublishingWeb
Hinweis |
---|
Der Microsoft.SharePoint.Publishing-Namespace ist Bestandteil von SharePoint Server 2010. Der Inhalt dieses Abschnitts bezieht sich auf SharePoint Server 2010 und nicht auf SharePoint Foundation 2010. |
Über die GetPublishingWebs-Methode der PublishingWeb-Klasse wird ein PublishingWebCollection-Objekt zurückgegeben. Sie müssen die Close-Methode für jedes aufgezählte innerPubWeb-Objekt aufrufen. Wenn Sie nur die GetPublishingWeb-Methode aufrufen, ist es nicht erforderlich, auch Close aufzurufen.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_300" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void PublishingWebCollectionLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Passing in SPWeb object that you own, no dispose needed on
// outerPubWeb.
PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);
PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();
foreach (PublishingWeb innerPubWeb in pubWebCollection)
{
// innerPubWeb leak.
}
// PublishingWeb will leak for each innerPubWeb referenced
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub PublishingWebCollectionLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
' Passing in SPWeb object that you own, no dispose needed on
' outerPubWeb.
Dim outerPubWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web)
Dim pubWebCollection As PublishingWebCollection = outerPubWeb.GetPublishingWebs()
For Each innerPubWeb As PublishingWeb In pubWebCollection
' innerPubWeb leak.
Next
' PublishingWeb will leak for each innerPubWeb referenced
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void PublishingWebCollectionNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
// Passing in SPWeb object that you own, no dispose needed on
// outerPubWeb.
PublishingWeb outerPubWeb = PublishingWeb.GetPublishingWeb(web);
PublishingWebCollection pubWebCollection = outerPubWeb.GetPublishingWebs();
foreach (PublishingWeb innerPubWeb in pubWebCollection)
{
try
{
// ...
}
finally
{
if(innerPubWeb != null)
innerPubWeb.Close();
}
}
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub PublishingWebCollectionNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
' Passing in SPWeb object that you own, no dispose needed on
' outerPubWeb.
Dim outerPubWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web)
Dim pubWebCollection As PublishingWebCollection = outerPubWeb.GetPublishingWebs()
For Each innerPubWeb As PublishingWeb In pubWebCollection
Try
' ...
Finally
If innerPubWeb IsNot Nothing Then
innerPubWeb.Close()
End If
End Try
Next
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Hinweis |
---|
Entsprechend ist es notwendig, Close für jedes PublishingWeb-Objekt aufzurufen, das durch Aufrufen der Add-Methode für das von Microsoft.SharePoint.Publishing.PublishingWeb.GetPublishingWebs zurückgegebene PublishingWebCollection-Objekt erstellt wurde. Ein Codebeispiel hierfür finden Sie im Rahmen der GetPublishingWebs()-Methode. In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_310" identifizierte Problem beschrieben. |
Es wird ein PublishingWeb-Objekt von der Microsoft.SharePoint.Publishing.PublishingWeb.GetVariation-Methode zurückgegeben, das verworfen werden muss.
Hinweis |
---|
In dieser bewährten Methode wird das von SharePoint Dispose Checker Tool als "SPDisposeCheckID_320" identifizierte Problem beschrieben. |
Beispiel für schlechten Code
void GetVariationLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in SPWeb object, so no Close() needed
VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];
PublishingWeb variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // Must be Closed().
// ...
} // SPWeb object outerWeb.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub GetVariationLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim publishingWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web) ' Passing in SPWeb object, so no Close() needed
Dim variationLabel As VariationLabel = Variations.Current.UserAccessibleLabels(0)
Dim variationPublishingWeb As PublishingWeb = publishingWeb.GetVariation(variationLabel) ' Must be Closed().
' ...
End Using ' SPWeb object outerWeb.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Beispiel für guten Code
void GetVariationNoLeak()
{
using (SPSite siteCollection = new SPSite("http://moss"))
{
using (SPWeb web = siteCollection.OpenWeb())
{
PublishingWeb variationPublishingWeb = null;
try
{
PublishingWeb publishingWeb = PublishingWeb.GetPublishingWeb(web); // Passing in SPWeb object, so no Close() needed.
VariationLabel variationLabel = Variations.Current.UserAccessibleLabels[0];
variationPublishingWeb = publishingWeb.GetVariation(variationLabel); // Must be Closed().
// ...
}
finally
{
if(variationPublishingWeb != null)
variationPublishingWeb.Close();
}
} // SPWeb object web.Dispose() automatically called.
} // SPSite object siteCollection.Dispose() automatically called.
}
Private Sub GetVariationNoLeak()
Using siteCollection As New SPSite("http://moss")
Using web As SPWeb = siteCollection.OpenWeb()
Dim variationPublishingWeb As PublishingWeb = Nothing
Try
Dim publishingWeb As PublishingWeb = PublishingWeb.GetPublishingWeb(web) ' Passing in SPWeb object, so no Close() needed.
Dim variationLabel As VariationLabel = Variations.Current.UserAccessibleLabels(0)
variationPublishingWeb = publishingWeb.GetVariation(variationLabel) ' Must be Closed().
' ...
Finally
If variationPublishingWeb IsNot Nothing Then
variationPublishingWeb.Close()
End If
End Try
End Using ' SPWeb object web.Dispose() automatically called.
End Using ' SPSite object siteCollection.Dispose() automatically called.
End Sub
Methodenübergreifende Muster für das Verwerfen von Objekten
Im folgenden Beispiel wird die gängige Regel veranschaulicht, die Objekte SPSite und SPWeb übergreifend über die Methoden in einer Klasse beizubehalten. In einigen Fällen ist dieses Entwurfsmuster notwendig. Achten Sie jedoch darauf, den richtigen Zeitpunkt zum Aufrufen von Dispose nach Abschluss der methodenübergreifenden Aufrufe nicht zu übersehen. Im folgenden Codebeispiel wird ein Muster veranschaulicht, bei dem SPSite und SPWeb Speicherverluste zur Folge haben, wenn die Klasse den Gültigkeitsbereich verlässt.
public class CrossMethodLeak
{
private SPSite _siteCollection = null;
private SPWeb _web = null;
public void MethodA()
{
_siteCollection = new SPSite("http://moss");
_web = _siteCollection.OpenWeb();
}
public void MethodB()
{
if (_web != null)
{
string title = _web.Title;
}
}
public void MethodC()
{
if (_web != null)
{
string name = _web.Name;
}
}
}
Public Class CrossMethodLeak
Private _siteCollection As SPSite = Nothing
Private _web As SPWeb = Nothing
Public Sub MethodA()
_siteCollection = New SPSite("http://moss")
_web = _siteCollection.OpenWeb()
End Sub
Public Sub MethodB()
If _web IsNot Nothing Then
Dim title As String = _web.Title
End If
End Sub
Public Sub MethodC()
If _web IsNot Nothing Then
Dim name As String = _web.Name
End If
End Sub
End Class
Schlussbemerkung
Da viele SharePoint-Objekte die IDisposable-Schnittstelle implementieren, müssen Sie bei der Verwendung dieser Objekte darauf achten, dass diese nicht im Arbeitsspeicher aufbewahrt werden. Wenn Sie die in diesem Artikel beschriebenen Richtlinien für das Verwerfen von SharePoint-Objekten befolgen, können Sie die Zuverlässigkeit Ihres benutzerdefinierten Codes sicherstellen.
Danksagung
Wir möchten uns bei den folgenden Personen für ihre Unterstützung und hilfreichen Hinweise beim Verfassen dieses Artikels bedanken:
Steve Sheppard, Microsoft Corporation
Chris Gideon, Microsoft Corporation
Rashid Aga, Microsoft Corporation
Siehe auch
Weitere Ressourcen
SharePoint Dispose Checker Tool
Patterns & Practices: Leitfaden zu SharePoint
Entwicklercenter für Windows SharePoint Services
Entwicklercenter für SharePoint Server 2007
Bewährte Methoden für die Anpassung von SharePoint-Produkte und -Technologien
Bewährte Methoden: Ressourcencenter für SharePoint Server 2007
Roger Lambs Blog für SharePoint-Entwickler
Bewährte Methoden: Häufige Codierprobleme beim Verwenden des SharePoint-Objektmodells