утечка памяти / плохо написанный код или и то, и другое - правильно избавиться от sqlconnection? - PullRequest
0 голосов
/ 17 января 2011

Я исследую проблему с веб-приложением .net 1.1, когда кажется, что у нас было довольно много исключений «Неустранимая ошибка внутреннего соединения», возможно, объекты соединения остаются открытыми или не удаляются должным образом. В конечном итоге веб-сервер падает при большой нагрузке. Я проверил код, и мы на самом деле вызываем sqlconnection.close () во всех местах в try catch, наконец

В проекте реализован следующий шаблон. Может кто-нибудь сказать мне, если это выглядит, как это может вызвать утечку памяти?

Веб-страница aspx выполняет следующий вызов в Private Sub Page_Load

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

где dbDictionary используется для получения таблицы sql из БД

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

Вот DBInteractionBase, который он наследует

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

Теперь, когда код выполняется, Dispose никогда не вызывается вызывающей веб-страницей. Что мне интересно, так это когда код утилизации выполняется GC? Возможно, я вижу еще одну проблему: если GetDictConnectionString имеет исключение, оно никогда не сбрасывает исходное исключение sql. Это как-то оставит объект sql в памяти? Имейте в виду, что это приложение .NET 1.1 и (сборщик мусора в .NET 1 не очень эффективен)

Также мне интересно, что я могу контролировать на веб-сервере, используя perfmon, чтобы показать утечку памяти. Я планирую изменить этот код и хотел бы индикатор, что проблема была решена. Я вижу тенденцию в SqlClient: Текущие пулы # соединений - они постоянно растут на 1000 каждый день (это текущее количество пулов, связанных с процессом.), Поэтому мне интересно, должно ли оно уменьшиться с уменьшением количества сеансов. Я смотрю (\ ASP.NET Apps v1.1.4322 ( Total ) \ Sessions Active), чтобы увидеть, как выглядит загрузка сервера.

1 Ответ

0 голосов
/ 06 марта 2011

Этот код:

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

создает два SqlConnection с (As New SqlConnection создает один), и первый никогда не будет уничтожен. Это, безусловно, может быть источником утечки соединений.

Вы также избавляетесь от соединения _connection, которое вы никогда не создавали (не видно, где оно создается). Предполагая, что он создается 1: 1, это не должно быть большой проблемой, но если перед вашим блоком Try возникает исключение, это соединение также не будет уничтожено. Если _connection не создается 1: 1 для этого кода, вы можете получить ObjectDisposedException, если кто-то попытается его использовать.

...