dr.*_*vil 12 c# regex memory .net-4.0 large-object-heap
如何在不引起LOH碎片的情况下在大字符串中运行大量RegExes(以查找匹配项)?
它是.NET Framework 4.0所以我正在使用StringBuilder它所以它不在LOH中但是一旦我需要在它上面运行一个RegEx,我必须调用StringBuilder.ToString()它意味着它将在LOH中.
有没有解决这个问题的方法?一个长期运行的应用程序几乎不可能处理大字符串和这样的RegExes.
解决这个问题的想法:
在考虑这个问题时,我想我找到了一个肮脏的解决方案.
在给定的时间我只有5个字符串,这5个字符串(大于85KB)将被传递给RegEx.Match.
由于碎片发生是因为新对象不适合LOH中的空白空间,这应该可以解决问题:
PadRight所有字符串最多 接受的大小,比方说1024KB(我可能需要这样做StringBuider)我想这个设计的最大问题是如果其他大对象在LOH中分配这个位置会导致应用程序分配大量1024 KB字符串,甚至可能会出现更糟糕的碎片.fixed语句可能有帮助但是如何在不实际创建不在固定内存地址中的新字符串的情况下向RegEx发送固定字符串?
关于这个理论的任何想法?(不幸的是我无法轻易地重现问题,我通常会尝试使用内存分析器来观察更改,并且不确定我可以为此编写哪种隔离测试用例)
好的,这是我尝试以相当通用的方式解决这个问题,但有一些明显的局限性.由于我没有在任何地方看到这个建议,每个人都抱怨LOH Fragmentation我想分享代码以确认我的设计和假设是正确的.
理论:
new StringBuilder(ChunkSize * 5); GCHandle.Alloc(pinnedText, GCHandleType.Pinned).即使LOH对象通常被固定,这似乎也改善了性能.也许是因为unsafe代码通过这种实现,下面的代码就像没有LOH分配一样工作.如果我切换到new string(' ')分配而不是使用静态StringBuilder或使用StringBuilder.ToString()代码可以在崩溃之前分配300%的内存outofmemory exception
我还使用内存分析器确认了结果,在此实现中没有LOH碎片.我仍然不明白为什么RegEx不会引起任何意外问题.我还测试了不同且昂贵的RegEx模式,结果相同,没有碎片.
码:
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
namespace LOH_RegEx
{
internal class Program
{
private static List<string> storage = new List<string>();
private const int ChunkSize = 100000;
private static StringBuilder _sb = new StringBuilder(ChunkSize * 5);
private static void Main(string[] args)
{
var pinnedText = new string(' ', ChunkSize * 10);
var sourceCodePin = GCHandle.Alloc(pinnedText, GCHandleType.Pinned);
var rgx = new Regex("A", RegexOptions.CultureInvariant | RegexOptions.Compiled);
try
{
for (var i = 0; i < 30000; i++)
{
//Simulate that we read data from stream to SB
UpdateSB(i);
CopyInto(pinnedText);
var rgxMatch = rgx.Match(pinnedText);
if (!rgxMatch.Success)
{
Console.WriteLine("RegEx failed!");
Console.ReadLine();
}
//Extra buffer to fragment LoH
storage.Add(new string('z', 50000));
if ((i%100) == 0)
{
Console.Write(i + ",");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine("OOM Crash!");
Console.ReadLine();
}
}
private static unsafe void CopyInto(string text)
{
fixed (char* pChar = text)
{
int i;
for (i = 0; i < _sb.Length; i++)
{
pChar[i] = _sb[i];
}
pChar[i + 1] = '\0';
}
}
private static void UpdateSB(int extraSize)
{
_sb.Remove(0,_sb.Length);
var rnd = new Random();
for (var i = 0; i < ChunkSize + extraSize; i++)
{
_sb.Append((char)rnd.Next(60, 80));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)