c# - 如何减少C#程序中Sql连接池占用的内存量

标签 c# sql-server-2008 out-of-memory

我有一个 C# 程序,它充当多线程 Web 服务器。它对保存在 Sql Server 数据库中的 Xml 结构进行大量处理。

随着这些 Xml 结构的大小增加,我发现应用内存不足。

我已经部署了 ANTS 内存分析器来查看发生了什么,并设法减少了处理过程中内存中保存的大字符串的数量,并做了一些改进。

但是,我现在留下了一个碎片化的大对象堆,这是由连接池中保存的大字节数组引起的。大字节数组是

TdsParserStateObject._bTmp
in TdsParser._physicalStateObj
in SqlInternalConnectionIds._parser
in DbConnectionInternal[0]
in DbConnectionPool._objectList

我 99.9% 确定我只在 using 语句中使用连接,尽管我确实在线程运行时为每个线程打开一个连接(这是一种优化,但我怀疑它是否会使事情变得更糟).

我可以对连接做些什么来减少它持有的内存量(除了关闭或处置它之外)吗?

或者我应该总是在每次使用时立即关闭或处置每个连接?

[稍后 - 根据我的评论] 我重构了代码,为每个数据库访问使用一个新连接,然后处理它(当然,事务除外,我从事务开始到结束使用相同的连接,并将其与事务一起处理)。

即使程序空闲(即没有使用中的连接),连接池中仍有连接占用大量内存,并导致碎片。

为什么已释放的连接会在连接池中占用 58MB 的内存?

[更晚] 我有一个解决方案可以防止 Sql Server 连接池将大堆碎片化 - 这是为了检测哪些连接可能有一个巨大的缓冲区,并标记它们以便在处理时从池中删除,使用

SqlConnection.ClearPool(连接)

我目前以一种相当 hacky 的方式执行此操作,方法是将 DataReader 子类化并检测返回的任何字段的大小是否超过 10MB。

欢迎提出有关检测哪些连接具有大缓冲区的更好方法的建议。

请注意,我已经恢复了在每次访问数据库时打开和处理连接的更改,因为跟踪在事务内部使用哪个连接(显然必须是事务)正在做我的工作.

在线程开始时打开并在结束时关闭的连接很好,因为几乎所有线程都是短暂的(作为对单个 Web 请求的响应)。异常(exception)情况是无论如何都可能在单个事务的上下文中运行的批处理。

最佳答案

使用 ADO.NET 时无需保持连接打开。默认情况下,连接将被合并(除非您自己关闭合并),ADO.NET 将完成池的所有管理工作。您甚至不必担心不同的用户凭据等,因为只有在连接参数相同时才会合并连接。从内存使用的角度来看,处理连接只会有帮助。

更多相关信息:

关于c# - 如何减少C#程序中Sql连接池占用的内存量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19868282/

相关文章:

c# - 如何在C#中获取多维数组的行/列的长度?

c# - 为什么 C# 允许进行异步覆盖?

sql-server - TSQL 使触发器静默失败

android通过web服务IIS或axis访问sql server?

java - 使用密码解密大文件时出现内存不足异常

android - 如何使用 Cursor.getString() 修复 OutOfMemory?

c# - WPF ObservableCollection<T> 与 BindingList<T>

c# - F# NativePtr.stackalloc 比 C# stackalloc 慢 - 包含反编译代码

c# - 恼人的 SQL 异常,可能是由于某些代码做错了

java - ActiveMQ 消费者 OutOfMemoryException