【发布时间】:2023-03-21 16:50:01
【问题描述】:
我最近在 WinForms 应用程序中查看了一些 .NET“内存泄漏”(即意外的、挥之不去的 GC 根对象)。加载然后关闭一个巨大的报告后,即使在进行了几次 gen2 收集之后,内存使用量也没有像预期的那样下降。假设报告控件由杂散事件处理程序保持活动状态,我打开 WinDbg 以查看发生了什么...
使用 WinDbg,!dumpheap -stat 命令报告字符串实例消耗了大量内存。使用!dumpheap -type System.String 命令进一步细化这一点,我发现了罪魁祸首,一个用于报告的 90MB 字符串,地址为 03be7930。最后一步是调用!gcroot 03be7930 以查看哪些对象使其保持活动状态。
我的预期不正确 - 它不是挂在报告控件(和报告字符串)上的未挂钩事件处理程序,而是由 System.Text.RegularExpressions.RegexInterpreter 实例持有,它本身是 System.Text.RegularExpressions.CachedCodeEntry 的后代。现在,Regex 的缓存(在某种程度上)是常识,因为这有助于减少每次使用 Regex 时都必须重新编译的开销。但这与让我的字符串保持活力有什么关系呢?
根据使用 Reflector 的分析,结果表明,每当调用 Regex 方法时,输入字符串都会存储在 RegexInterpreter 中。 RegexInterpreter 保留此字符串引用,直到随后的 Regex 方法调用将新字符串输入其中。我希望通过挂在 Regex.Match 实例和其他实例上来实现类似的行为。链条是这样的:
- Regex.Split、Regex.Match、Regex.Replace 等
- 正则表达式运行
- RegexScanner.Scan(RegexScanner 是基类,RegexInterpreter 是上述子类)。
- 正则表达式运行
有问题的正则表达式仅用于报告,很少使用,因此不太可能再次用于清除现有的报告字符串。即使稍后使用 Regex,它也可能正在处理另一份大型报告。这是一个相对严重的问题,只是感觉很脏。
综上所述,我找到了一些关于如何解决或至少解决这种情况的选项。我会先让社区做出回应,如果没有人站出来,我会在一两天内填补任何空白。
【问题讨论】:
-
您在创建正则表达式时是否使用了
Compiled选项? -
不,在这种情况下没有使用
Compiled选项。
标签: .net regex memory-leaks