我有一个充当多线程 Web 服务器的 C# 程序。它对 Sql Server 数据库中保存的 Xml 结构进行了大量处理。
随着这些 Xml 结构的大小增加,我发现应用程序内存不足。
我已经部署了 ANTS 内存分析器来查看发生了什么,并设法减少了处理过程中内存中保存的大字符串的数量,并稍微改进了一些东西。
但是,我现在留下了一个碎片化的大对象堆,这是由连接池中保存的大字节数组引起的。大字节数组是
TdsParserStateObject._bTmp
in TdsParser._physicalStateObj
in SqlInternalConnectionIds._parser
in DbConnectionInternal[0]
in DbConnectionPool._objectList
我 99.9% 确信我只在 using 语句中使用连接,尽管我确实在线程运行时保持每个线程打开一个连接(这是一种优化,但我怀疑它是否会让事情变得更糟)。
我可以对连接做些什么来减少它所拥有的内存量(除了关闭或处置它)?
还是我应该总是在每次使用时立即关闭或处理每个连接?
[后来-根据我的评论]我重构了代码以对每个数据库访问使用一个新连接,然后将其处理掉(当然,除了事务,我从事务的开始到结束都使用相同的连接,并且将其与交易一起处置)。
即使程序处于空闲状态(即没有正在使用的连接),连接池中仍有连接占用大量内存,并造成碎片。
为什么已处置的连接会在连接池中保留 58MB 的内存?
[Even later] 我有一个解决方案可以防止 Sql Server 连接池将大堆碎片化 - 这是为了检测哪些连接可能会有一个巨大的缓冲区,并标记它们以便在处理时从池中删除,使用
SqlConnection.ClearPool(连接)
我目前以一种相当老套的方式执行此操作,方法是对 DataReader 进行子类化并检测返回的任何字段是否超过 10MB。
欢迎提出有关检测哪些连接具有大缓冲区的更好方法的建议。
请注意,我已经恢复了在每次数据库访问时打开和处理连接的更改,因为跟踪在事务中使用哪个连接(显然必须是事务)正在做我的工作。
在线程开始时打开并在结束时关闭的连接很好,因为几乎所有线程都是短暂的(作为对单个 Web 请求的响应)。例外情况是可能在单个事务的上下文中运行的批处理过程。