.NET Regex示例缓存

abithluo  于 2023-10-22  发布在  .NET
关注(0)|答案(3)|浏览(127)

我读过this article,它描述了如何使用.NET正则表达式调用示例与静态方法。
但是,如果变量本身是静态的呢?有没有人知道.NET是否做了任何可能导致内存泄漏的缓存?
澄清一下。举例来说:

public static Regex Foo = new Regex(@"(?:,.*)");

对比:

public static void MyMethod(){
  Regex Foo = new Regex(@"(?:,.*)");
}

其中一个比另一个更容易导致记忆问题吗?我知道第二个示例显然会创建更多的示例,但是第一个示例是否需要担心传入字符串的缓存,因为它基本上会永远闲置。

ax6ht2ek

ax6ht2ek1#

如果你有一个示例化的Regex对象,并且你只是在它上面调用示例方法,那么缓存(根据提供的文章)将不会发生。如果你创建Regex对象并将其作为静态属性存储在类中,你仍然在处理一个示例化的对象,因此缓存不会发生(>=.net 2.0)。
另一方面,每次调用Regex静态方法(如Regex.Match(“bla”,“bla”))时,解析和编译的正则表达式将被缓存。
编辑
看看您的示例,在这两种情况下都不会发生缓存。然而,如果第二个例子是:

Match m=Regex.Match(@"(?:,.*)",someString);

.那么编译后的正则表达式(?:,.*)将被缓存,因此您可以高效地对Regex.Match(@"(?:,.*)",...进行后续调用,而无需重新解析/重新编译表达式(?:,.*)。我想就内存消耗而言,这几乎等同于保留一个静态示例。另一方面,如果提供给Regex.Match的正则表达式发生了变化,那么将以某种(可能可以忽略不计的)代价生成一个额外的条目。

ryevplcw

ryevplcw2#

没有“静态示例”这样的东西--只有引用对象的静态 * 变量 *。同一个对象可以被示例变量、局部变量或静态变量引用。它不会改变Regex构造函数中的任何代码。

uurv41yg

uurv41yg3#

System.Text.RegularExpressions.Regex类中,框架将在运行时为您做一些缓存。它在缓存它们之前编译它们。但是,只有在使用static Regex方法时才能利用缓存,如下所述。这从.NET Framework 1.0开始就存在了,直到今天(目前是.NET 8)仍然存在。只有在以下几种情况下才有意义使用内置缓存:

什么时候使用“内置”Regex缓存?

1.在整个应用程序域中使用的不同正则表达式少于 * 16个。这是因为缓存的正则表达式是有限制的,并且这个值是Regex类的静态成员(即,由Regex的所有示例共享。此限制的大小由Regex.CacheSize属性控制。它的默认值为15(迄今为止,所有.NET版本都是如此)。如果需要,可以更改此值。我通常不建议这样做-见建议#1。
1.正则表达式是“常量”--表示它的字符串不一定是常量(尽管这是个好主意),但它在每次调用时都不会改变。

如何使用Regex内置缓存?

利用缓存的唯一方法是使用static方法Regex.IsMatch(...)Regex.Match(...)。在你的例子中,你会这样做:

public static void MyMethod(string testInput)
{
    bool isMatch = Regex.IsMatch(testInput, @"(?:,.*)");
    ...
}

建议

1.我不喜欢把缓存留给框架的想法,主要是因为你可能会在将来的某个时候使用额外的静态正则表达式,在另一个类中使用静态正则表达式,或者在另一个dll中使用静态正则表达式,甚至是你不知道的第三方依赖项!因此,我通常创建一个static readonly Regex示例作为使用它的类的成员,并根据需要重用它:

private static readonly Regex _myRegex = new Regex(@"(?:,.*)", RegexOptions.Compiled /* add any other RegexOptions you need here as well */);

1.使用RegexOptions.Compiled是一个好主意,因此它被编译为MSIL代码,而不是在运行时被解释。编译的正则表达式以最少的初始化时间为代价,最大限度地提高了运行时性能-请参阅RegexOptions

相关问题