C # geheugenlek?

De volgende code crasht na enige tijd als gevolg van een hoog geheugengebruik (ik open taskmanager en het gebruikte geheugen blijft toenemen). Maar ik zie geen enkel geheugenlek, behalve dat garbagecollection zijn werk niet doet. Suggesties?

//Load a list of regex
//Load a list of phrases
//Open a output file

foreach (string regexString in regexList)
{
    int num = 0;

    Regex regex = new Regex(regexString, RegexOptions.Compiled | RegexOptions.IgnoreCase);

    foreach (string phrase in phraseList)
            num += regex.Matches(phrase).Count;

    if (num > 0)
    {
        output.WriteLine(String.Join(" ", num, phrase));
        output.Flush();
    }
}

BEWERK:

Complete Code: http://pastebin.com/0SQYn44z

EDIT2:

Ik vond en plaatste de oplossing (voor elke lus) Bedankt voor iedereen die toch probeerde te helpen.

4
stel voor dat je een betere tool gebruikt dan task manager om geheugen te bekijken, RedGate.com is het populairst. U noemt de GC zijn werk niet, het werkt niet deterministisch ... er is geen manier om te weten wanneer het een verzameling begint. Eigenlijk om dit porblem op te lossen, moet je de geheugendump van de OOM vastleggen en een diagnose stellen met WinDbg.
toegevoegd de auteur Jeremy Thompson, de bron
Bedankt voor de code maar om het probleem te reproduceren krijg ik een uitzondering over data.xml - kunnen we dit bestand zien?
toegevoegd de auteur Jeremy Thompson, de bron
wat is uitvoer ?
toegevoegd de auteur Daniel A. White, de bron
Waarom niet gewoon debuggen en er één stap over doen? Im raden de foreach duurt veel langer dan je had verwacht (misschien inefficiënte regexp, of veel lookahead/lookbehind).
toegevoegd de auteur carpii, de bron
Is er een specifieke reguliere expressie die het probleem veroorzaakt, of is het alleen als je er veel van hebt?
toegevoegd de auteur Mark Byers, de bron
@ DanielA.White Het lijkt op een omleiding naar Console
toegevoegd de auteur Cole Johnson, de bron
De links naar de gegevens zijn al dood. Voeg een voorbeeld van beide databestanden toe aan de vraag.
toegevoegd de auteur Henk Holterman, de bron
toegevoegd de auteur David Benko, de bron
uitvoer is StreamWriter
toegevoegd de auteur David Benko, de bron
de regexes zijn allemaal in dit formaat: \ bsomeword1 someword2 \ b en ik heb er ongeveer 300k van en ongeveer 60k frases
toegevoegd de auteur David Benko, de bron
Welk type stream schrijft de StreamWriter?
toegevoegd de auteur mlorbetske, de bron

5 antwoord

Ik kan aan uw voorbeeld niet zien, maar het is mogelijk dat de vlag RegexOptions.Compiled het probleem veroorzaakt. Van msdn:

Compiled geeft aan dat de reguliere expressie is gecompileerd naar een assembly. Dit levert een snellere uitvoering op, maar verlengt de opstarttijd. Deze waarde moet niet worden toegewezen aan de eigenschap Options bij het aanroepen van de methode CompileToAssembly.

Als een regex is gecompileerd voor een assembly, kan de gegenereerde code pas worden ontladen als u de toepassing opnieuw start. Net laadt geen assembly's leeg.

Dit betekent dat als u veel verschillende reguliere expressies heeft en u ze niet opnieuw gebruikt, een gecompileerde Regex meestal geen goed idee is.

6
toegevoegd
Ik denk dat Compiled tegenwoordig standaard is.
toegevoegd de auteur Henk Holterman, de bron
Oké, maar stop toch met het gebruik van de gecompileerde optie. Zoals je het gebruikt, kan het onmogelijk genoeg goed doen om zijn eigen kosten te compenseren.
toegevoegd de auteur Alan Moore, de bron
@HenkHolterman - Ik heb zojuist naar de broncode van Regex gekeken en het lijkt erop dat Compiled standaard niet wordt gebruikt. Dit is in overeenstemming met de msdn-documentatie: msdn.microsoft.com/en-us/library/…
toegevoegd de auteur Elian Ebbing, de bron
Je hebt gelijk, ik heb het verwijderd en het programma liep veel sneller
toegevoegd de auteur David Benko, de bron
Ik heb geprobeerd zonder RegexOptions.Compiled en het probleem blijft bestaan
toegevoegd de auteur David Benko, de bron

De kans bestaat dat uw regex overmatige backtrack gebruikt, wat resulteert in een lange uitvoeringstijd en een hoog geheugengebruik

Kun je de regex en de invoer plaatsen zodat ik het zeker kan controleren?

2
toegevoegd
Ik zie dat je het zelf hebt uitgevonden toch?
toegevoegd de auteur buckley, de bron
de nacht is gevallen. Ik heb morgen een kijkje genomen
toegevoegd de auteur buckley, de bron
Je programma staat niet op zichzelf, ik krijg: Kon bestand 'C: \ Program Files (x86) \ LINQPad \ data.xml' niet vinden.
toegevoegd de auteur buckley, de bron
OK, bestel je een klein codevoorbeeld en maak je het beschikbaar om te downloaden? Ik heb veel C# regexes gedaan, dus kan het uitvoeren en diagnosticeren
toegevoegd de auteur buckley, de bron
Ok ik upload data.xml wacht even
toegevoegd de auteur David Benko, de bron
toegevoegd de auteur David Benko, de bron
De regex zijn allemaal in dit formaat: \ bsomeword1 someword2 \ b en ik heb er ongeveer 300k van en ongeveer 60k-zinnen met een lengte van avarege 500 tekens
toegevoegd de auteur David Benko, de bron

U gebruikt enkele typen die IDisposable implementeren zonder Dipose() aan te roepen:

  • StreamReader
  • StreamWriter
  • XmlReader

Wikkel het gebruik van die typen in het gebruik van uitspraken en kijk of dat iets voor jou verbetert.

1
toegevoegd
@HenkHolterman regels 33, 34 en 71 van het monster gepost op pastebin.
toegevoegd de auteur Asik, de bron
Geef (een van) deze gevallen aan in de verstrekte code.
toegevoegd de auteur Henk Holterman, de bron
Als u de Reader sluit, wordt de Stream gesloten. Maar zelfs als ze allemaal open blijven, kan dit de resultaten die het OP krijgt niet verklaren.
toegevoegd de auteur Henk Holterman, de bron

Nadat ik je code heb gezien, kan ik al aanbevelen om niet twee, maar één gecombineerde Regex te gebruiken. Zoiets als:

Regex regex = new Regex(
        @"\b(?:" + s1 + " " + s2 + "|" + s2 + " " + s1 + @")\b",
        RegexOptions.IgnoreCase);

Merk op dat de reeks + -operatoren daar wordt geconverteerd naar een enkele String.Concat (params string []) -aanroep. Met slechts 2 tot 4 delen zou het niet eens de tijdelijke array maken omdat er voor dat geval meer gespecialiseerde Concat overbelastingen zijn. Join gebruikt altijd een tijdelijke array en moet ook de scheidingstekenreeks verzorgen, ook als deze leeg is.

Een ander ding dat je misschien wilt onthouden, is dat het uitvoeren van je programma in de debug-modus nogal zal verschillen van het uitvoeren in de releasemodus. De lijst trefwoorden blijft bijvoorbeeld levend totdat de functie terugkeert. Ik raad aan om de levensduur ervan expliciet te beperken en ook om de andere objecten zo snel mogelijk op te ruimen. Misschien iets als het volgende:

string[] keywordArray;
using (StreamReader keywordsFile = new StreamReader("keywords.txt"))
{
    List keywords = new List();
    string keyword;
    while ((keyword = keywordsFile.ReadLine()) != null)
        keywords.Add(keyword);

    keywordArray = keywords.ToArray();
}

Of sla het helemaal over:

string[] keywordArray = File.ReadAllLines("keywords.txt");//internally uses above code

Op de een of andere manier heb ik echter het gevoel dat je je enorme feeds-bestand als geheel in het geheugen laadt, een slecht idee. Het zou veel minder geheugen vereisen als je één FeedItem tegelijk zou kunnen deserialiseren en terugsturen van een iteratormethode . Daarna hoeft u alleen nog het algoritme te herstructureren zodat de loop-over-feeditems de buitenste lus vormen.

1
toegevoegd
Ik heb de oplossing gevonden en gepost, maar echt bedankt voor je adviezen over betere werkwijzen, ze waren helemaal nuttig
toegevoegd de auteur David Benko, de bron

Laten we kijken of ik dit goed heb. Je hebt een grote lijst met trefwoorden en voor elke permutatie van twee van die woorden maak je een nieuwe string door ze samen te voegen met een spatie in het midden, plus een andere string in de volgorde van de omgekeerde woorden (wat onnodig is, BTW) . Ten slotte maakt u een Regex-object van elk van de tekenreeksen.

Als je dat hebt gedaan, begin je te herhalen over je lijst met FeedItem-objecten, neem je twee attributen van elk en vorm je ze in een string zoals je deed met de sleutelwoorden, en probeer je die string te matchen met elk van de twee regexes. Kortom, ik denk dat je voorlopig de vinger moet wijzen en je moet concentreren op het herwerken van je code. Sterker nog, ik raad je aan om voorlopig Regexes te vergeten. Je gebruikt hun kracht niet en ze leiden je af van je echte problemen.

1
toegevoegd