如何找到泄漏的数据库连接池句柄?

Jes*_*sse 16 asp.net connection-pooling

我看到了可怕的"在从池中获取连接之前超时时间已过去"错误.

我搜索了代码中任何未闭合的数据库连接,但找不到任何.

我想要做的是:下次我们收到此错误时,让系统转储一个列表,其中包含哪些proc或http请求持有所有句柄,因此我可以找出导致问题的代码.

更好的是看看这些手柄有多长时间,所以我可以发现使用但未封闭的连接.

有没有办法做到这一点?

LOA*_*OAS 15

如果您足够幸运,连接创建/打开是集中的,那么下面的类应该可以很容易地发现泄漏的连接.请享用 :)

/// <summary>
/// This class can help identify db connection leaks (connections that are not closed after use).
/// Usage:
/// connection = new SqlConnection(..);
/// connection.Open()
/// #if DEBUG
/// new ConnectionLeakWatcher(connection);
/// #endif
/// That's it. Don't store a reference to the watcher. It will make itself available for garbage collection
/// once it has fulfilled its purpose. Watch the visual studio debug output for details on potentially leaked connections.
/// Note that a connection could possibly just be taking its time and may eventually be closed properly despite being flagged by this class.
/// So take the output with a pinch of salt.
/// </summary>
public class ConnectionLeakWatcher : IDisposable
{
    private readonly Timer _timer = null;

    //Store reference to connection so we can unsubscribe from state change events
    private SqlConnection _connection = null;

    private static int _idCounter = 0;
    private readonly int _connectionId = ++_idCounter;

    public ConnectionLeakWatcher(SqlConnection connection)
    {
        _connection = connection;
        StackTrace = Environment.StackTrace;

        connection.StateChange += ConnectionOnStateChange;
        System.Diagnostics.Debug.WriteLine("Connection opened " + _connectionId);

        _timer = new Timer(x =>
        {
            //The timeout expired without the connection being closed. Write to debug output the stack trace of the connection creation to assist in pinpointing the problem
            System.Diagnostics.Debug.WriteLine("Suspected connection leak with origin: {0}{1}{0}Connection id: {2}", Environment.NewLine, StackTrace, _connectionId);
            //That's it - we're done. Clean up by calling Dispose.
            Dispose();
        }, null, 10000, Timeout.Infinite);
    }

    private void ConnectionOnStateChange(object sender, StateChangeEventArgs stateChangeEventArgs)
    {
        //Connection state changed. Was it closed?
        if (stateChangeEventArgs.CurrentState == ConnectionState.Closed)
        {
            //The connection was closed within the timeout
            System.Diagnostics.Debug.WriteLine("Connection closed " + _connectionId);
            //That's it - we're done. Clean up by calling Dispose.
            Dispose();
        }
    }

    public string StackTrace { get; set; }

    #region Dispose
    private bool _isDisposed = false;

    public void Dispose()
    {
        if (_isDisposed) return;

        _timer.Dispose();

        if (_connection != null)
        {
            _connection.StateChange -= ConnectionOnStateChange;
            _connection = null;
        }

        _isDisposed = true;
    }

    ~ConnectionLeakWatcher()
    {
        Dispose();
    }
    #endregion
}
Run Code Online (Sandbox Code Playgroud)


Mr *_*ose 5

监控连接池有一些很好的链接.谷歌搜索".net连接池监控".

我前面提到过的一篇文章Bill Vaughn的文章(请注意,这篇文章虽旧,但仍包含有用信息).它有关于监控连接池的一些信息,但也有一些关于泄漏可能发生的深刻见解.

他建议,为监测;

"监控连接池

好的,所以你打开一个连接并关闭它,想知道连接是否仍然存在 - 在充气床垫的连接池中萎缩.好吧,有几种方法可以确定有多少连接仍然存在(仍然连接)甚至是他们正在做什么.我在这里和我的书中讨论了其中的几个:

·将SQL事件探查器与SQLProfiler TSQL_Replay模板一起用于跟踪.对于那些熟悉Profiler的人来说,这比使用SP_WHO进行轮询更容易.

·运行SP_WHO或SP_WHO2,它在sysprocesses表中返回显示每个进程当前状态的所有工作进程的信息.通常,每个连接都有一个SPID服务器进程.如果您使用连接字符串中的Application Name参数命名连接,则很容易找到.

·使用性能监视器(PerfMon)监视池和连接.我接下来详细讨论这个问题.

·在代码中监视性能计数器.此选项允许您显示或仅监视连接池的运行状况和已建立的连接数.我将在本文的后续部分讨论这个问题."

编辑:

与往常一样,请查看SO 上的其他类似帖子

第二编辑:

一旦确认池没有回收连接,您可以尝试的另一件事是利用StateChange事件来确认何时打开和关闭连接.如果您发现打开的状态更改比关闭更多,那么这表明某处存在泄漏.然后,您还可以在statechanged事件中记录数据以及时间戳,如果您在应用程序上有任何其他日志记录,则可以开始解析日志文件,以查看似乎状态更改为关闭以打开的情况,没有相应的开放关闭.有关如何处理StateChangedEvent的更多信息,请参阅此链接.