我有一个 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/