我看到了可怕的“在从池中获取连接之前超时时间已过去”错误。
我在代码中搜索了任何未关闭的数据库连接,但找不到任何。
我想要做的是:下次我们收到此错误时,让系统转储一个列表,其中包含哪些proc或http请求包含所有句柄,因此我可以找出导致问题的代码。< / p>
更好的是看看这些句柄持有多长时间,所以我可以发现已使用但未封闭的连接。
有没有办法做到这一点?
答案 0 :(得分: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
}
答案 1 :(得分:5)
监控连接池有一些很好的链接。谷歌搜索“.net连接池监控”。
我前面提到过的一篇文章是Bill Vaughn's article(注意这是旧的,但仍然包含有用的信息)。它有关于监控连接池的一些信息,但也有一些关于泄漏可能发生的深刻见解。
对于监控,他建议;
“监控连接池
好的,所以你打开一个连接并关闭它,想知道是否 连接仍然存在 - 在连接池中枯竭 充气床垫。好吧,有几种方法可以确定多少 连接仍然存在(仍然连接)甚至他们 是做。我在这里和我的书中讨论了其中的几个:
·将SQL事件探查器与SQLProfiler TSQL_Replay一起使用 跟踪模板。对于那些熟悉Profiler的人, 这比使用SP_WHO进行轮询更容易。
·运行SP_WHO或SP_WHO2,它们从中返回信息 显示当前状态的所有工作进程的sysprocesses表 每个过程。通常,每个SPID服务器进程一个 连接。如果使用“应用程序名称”命名连接 在连接字符串中的参数,它很容易找到。
·使用性能监视器(PerfMon)监视池 和连接。我接下来会详细讨论这个问题。
·在代码中监控性能计数器。此选项允许 您要显示或只是监视连接池的运行状况 和已建立的连接数。我在讨论这个 本文的后续部分。“
修改:
与往常一样,在SO
上查看一些other similar posts第二次修改:
一旦确认池没有回收连接,您可以尝试的另一件事是利用StateChange事件来确认何时打开和关闭连接。如果您发现打开的状态更改比关闭更多,那么这表明某处存在泄漏。然后,您还可以在statechanged事件中记录数据以及时间戳,如果您在应用程序上有任何其他日志记录,则可以开始解析日志文件,以查看似乎状态更改为关闭以打开的情况,没有相应的开放关闭。有关如何处理StateChangedEvent的更多信息,请参阅this link。
答案 2 :(得分:0)
我用过这个
http://www.simple-talk.com/sql/performance/how-to-identify-slow-running-queries-with-sql-profiler/
以前找到长时间运行的存储过程,然后我可以返回并找到调用SP的方法。
不知道这是否有帮助