0

Ich untersuche ein Problem mit einer. NET 1.1 Webanwendung, wo es scheint, dass wir ziemlich viele "Internal connection fatal error" Ausnahmen möglicherweise die Verbindungsobjekte offen oder nicht ordnungsgemäß entsorgt haben. Der Webserver stürzt schließlich unter hoher Last ab. Ich überprüfte den Code und wir rufen in der Tat sqlconnection.close() an allen Stellen in der Try Catch schließlichSpeicherleck/schlecht geschriebenen Code oder beides - ordnungsgemäße Entsorgung von sqlconnection?

Das Projekt implementiert das folgende Muster. Kann mir jemand sagen, ob es so aussieht, als könnte dies zu einem Speicherleck führen?

Die aspx Webseite macht den folgenden Aufruf in Private Sub Page_Load

Dim oDictionary As New dbDictionary 
tagVal = oDictionary.GetTag(41) 

wo dbDictionary für das Erhalten einer SQL-Tabelle von DB verwendet wird

Public Class dbDictionary 
    Inherits DBInteractionBase 

Public Function GetTag(ByVal tagId) 

     'uses the _connection connection object and Executes sql which sometimes throws a sql exception, but closes the connection in finally 

     GetDictConnectionString() 

     'new sqlconnection object for another sqlcommand 
     Dim dictConnection As New SqlConnection 
     dictConnection = _connection 'At this point the _connection is closed. 

     'I think the dictConnection is a reference to _connection 

     Dim cmdToExecute As SqlCommand = New SqlCommand 

     ' // Use base class' connection object 
     cmdToExecute.Connection = dictConnection 

     Try 
      ' // Open connection. 
      dictConnection.Open() 

      ' // Execute query. 
      adapter.Fill(toReturn) 


     Catch ex As Exception 
      Throw New Exception("Error occured.", ex) 
     Finally 
      ' // Close connection. 
      dictConnection.Close() 
      cmdToExecute.Dispose() 
      adapter.Dispose() 
     End Try 


    End Function 

    Private Function GetDictConnectionString() 


     ' initialize SqlCommand... Use base class _connection object 
     cmdToExecute.Connection = _connection 

     Try 
      _connection.Open() 
      adapter.Fill(toReturn) 

     Catch ex As Exception 
      Return "Error" ' Could this be the issue? The original exception isn't released? 
     Finally 
      _connection.Close() 
      cmdToExecute.Dispose() 
      adapter.Dispose() 
     End Try 

End Class 

Hier ist die DBInteractionBase, dass es erbt

Public MustInherit Class DBInteractionBase 
    Inherits System.Web.UI.Page 

Protected _connection As SqlConnection 

    Public Sub New() 

     _connection = New SqlConnection 
     _connection.ConnectionString = "some conn string" 
      End Sub 

    Public Overloads Sub Dispose() 
     Dispose(True) 
     GC.SuppressFinalize(Me) 
    End Sub 


    Protected Overridable Overloads Sub Dispose(ByVal isDisposing As Boolean) 
     ' // Check to see if Dispose has already been called. 
     If Not _isDisposed Then 
      If isDisposing Then 
       ' // Dispose managed resources. 
       _connection.Dispose() 
       _connection = Nothing 
      End If 
     End If 
     _isDisposed = True 
    End Sub 

Jetzt, wenn der Code ausgeführt wird, ruft Dispose nie einen Anruf ab Ed von der aufrufenden Webseite. Was ich mich wundere ist, wenn der Verfügungscode überhaupt vom GC ausgeführt wird? Ein anderes Problem, das ich möglicherweise sehe, ist, dass, wenn GetDictConnectionString eine Ausnahme hat, es niemals die ursprüngliche sql-Ausnahme wiederholt. Würde das das sql-Objekt irgendwie im Speicher belassen? Denken Sie daran, diese eine Anwendung .NET 1.1 ist und (GC in .NET 1 ist nicht sehr effizient)

Auch ich frage mich, was ich auf dem Web-Server mit Perfmon überwachen kann einen Speicherverlust anzuzeigen. Ich plane, diesen Code zu ändern und möchte einen Indikator, dass das Problem behoben wurde. Ich sehe einen Trend in SqlClient: Aktuelle # Verbindungspools - es wächst stetig 1000 jeden Tag (Es ist die aktuelle Anzahl der Pools mit dem Prozess verbunden.) Ich frage mich also, ob es gehen sollte, wie die Sitzungen sinken. Ich schaue (\ ASP.NET Apps v1.1.4322 (Gesamt) \ Sitzungen aktiv), um zu sehen, wie die Serverlast aussieht.

+0

Warum deklarieren Sie dictConnection als eine neue SqlConnction und dann auf die bestehende _connection? Ich sollte auch darauf hinweisen, dass Sie SqlConnections nicht wirklich loswerden wollen. Wenn Sie Schließen ausführen, werden sie an den Verbindungspool zurückgegeben. Sobald Sie die gleiche Verbindungszeichenfolge verwenden, werden sie automatisch wiederverwendet. – tomasmcguinness

+0

Ich weiß nicht, warum sie ein neues sqlconnection-Objekt deklarieren, aber das ist auf meiner Liste zu refactor. Ich möchte nur wissen, ob das Auswirkungen auf die Probleme hat, die wir haben. Wenn Sie das SqlConnection-Objekt nicht ordnungsgemäß entsorgen, hat es die Möglichkeit, im Speicher zu verweilen? – kiev

+0

SqlConnections wird standardmäßig beibehalten, aber für die Leistung ist das im Allgemeinen eine gute Sache, und es sollte nur die Anzahl der gepoolten Objekte auf eine festgelegte Größe erhöhen. – tomasmcguinness

Antwort

0

Dieser Code:

'new sqlconnection object for another sqlcommand 
Dim dictConnection As New SqlConnection 
dictConnection = _connection 'At this point the _connection is closed. 

schafft zwei SqlConnection s (die As New SqlConnection schafft ein), und die erste würde nie entsorgt werden. Dies könnte sicherlich eine Quelle für undichte Verbindungen sein.

Sie verfügen auch über die Verbindung _connection, die Sie nie erstellt haben (kann nicht sehen, wo diese erstellt wird). Angenommen, es wird 1: 1 erstellt, sollte dies kein großes Problem sein, aber wenn eine Ausnahme vor Ihrem Try Block auftritt, wird diese Verbindung auch nicht entsorgt. Wenn _connection nicht 1: 1 für diesen Code erstellt wird, erhalten Sie möglicherweise ObjectDisposedException, wenn etwas anderes versucht, es zu verwenden.