.NET RegEx"内存泄漏"调查

Kev*_*lin 14 .net regex memory-leaks

我最近在WinForms应用程序中查看了一些.NET"内存泄漏"(即意外的,挥之不去的GC根源对象).在加载然后关闭一个巨大的报告之后,即使在几个gen2集合之后,内存使用量也没有像预期的那样下降.假设报告控件被一个迷路事件处理程序保持活着,我破解了打开WinDbg以查看发生了什么......

使用WinDbg,该!dumpheap -stat命令报告了字符串实例消耗了大量内存.使用!dumpheap -type System.String命令进一步完善了这一点,我找到了罪魁祸首,一个用于报告的90MB字符串,地址为03be7930.最后一步是调用!gcroot 03be7930以查看哪些对象保持活着状态.

我的期望是不正确的 - 它不是一个悬挂在报告控件(和报告字符串)上的非挂钩事件处理程序,而是由一个System.Text.RegularExpressions.RegexInterpreter实例保留,该实例本身是一个的后代System.Text.RegularExpressions.CachedCodeEntry.现在,Regexs的缓存(有点)是常识,因为这有助于减少每次使用时重新编译Regex的开销.但是,这与保持我的弦活着有什么关系呢?

基于使用Reflector的分析,事实证明只要调用Regex方法,输入字符串就存储在RegexInterpreter中.RegexInterpreter保留此字符串引用,直到通过后续Regex方法调用将新字符串输入其中.我希望通过挂在Regex.Match实例上以及其他可能的类似行为.链是这样的:

  • Regex.Split,Regex.Match,Regex.Replace等
    • Regex.Run
      • RegexScanner.Scan(RegexScanner是基类,RegexInterpreter是上面描述的子类).

违规的Regex仅用于报告,很少使用,因此不太可能再次用于清除现有的报告字符串.即使后来使用正则表达式,也可能会处理另一份大型报告.这是一个相对重要的问题,只是简单的感觉很脏.

总而言之,我找到了一些关于如何解决或至少解决这种情况的选项.我会先让社区回复,如果没有人提出来,我会在一两天内填补空缺.

Jos*_*osh 8

您使用的是Regex实例还是采用字符串模式的静态Regex方法?根据这篇文章,Regex实例不参与缓存.

  • 是的,静态正则表达式方法的使用是罪魁祸首.您可以通过Reflector验证静态方法是否使用了缓存 - 所有静态调用都使用带有'useCache'参数的私有ctor创建一个Regex.这里的简单解决方案是不使用静态方法.缓存并不重要,因为与处理巨大的输入字符串相比,编译是微不足道的.根据Regex的使用方式,其他可能有用的解决方案是通过将Regex.CacheSize设置为0或在处理源之后通过Regex运行空字符串来禁用Regex缓存. (2认同)