Regex i outofmemory

0

Witam
Przy takim kodzie(ponizej) wywala mi komunikat "OUTOFMEMORY".
A dokladniej, za pierwszym przejsciem przez funkcje change_to_xml(), program wciaga prawie 800MB pamieci, ale jej potem nie zwalnia, tylko dopisuje. Kiedy, x==2 i znowu wywolywana jest ta funkcja, wtedy wywala mi ten komunikat. Tekst, ktory jest wczytywany z pliku zajmuje max. 6MB.
Kiedy zrobilem to poprzez plik.Replace, to ladnie mi czyscilo pamiec, ale za to nie wszystkie znaki mi usuwal:(
W jaki sposob zwalniac pamiec, ktora Regex zapelnia ?

private void test()
{
   for(int x=1;x<10;x++)
   {
     plik="";
     plik = File.ReadAllText(@"c:\jakis tam plik.xml");
     change_to_xml();
     File.WriteAllText(@"c:\"+x.ToString()+".xml", plik.ToString(), Encoding.UTF8);
   }
   MessageBox.Show("koniec");
}
        private void change_to_xml()
        {
            plik = Regex.Replace(plik, Convert.ToString('"'), Convert.ToString("'"));
            plik = Regex.Replace(plik, "<Table>", "");
            plik = Regex.Replace(plik, "</Table>", "");
            plik = Regex.Replace(plik, "<ms>", "");
            plik = Regex.Replace(plik, "</ms>", "");
            plik = Regex.Replace(plik, "&lt;", "<");
            plik = Regex.Replace(plik, "&gt;", ">");
            plik = Regex.Replace(plik, "<ms xml:space='preserve'>", "");
            plik = Regex.Replace(plik, @"\<id_ms\>(.*)\</id_ms\>", "");
            plik = Regex.Replace(plik, "<?xml version='1.0' standalone='yes'?>", "");
            plik = Regex.Replace(plik, "<NewDataSet>", "");
            plik = Regex.Replace(plik, "</NewDataSet>", "");
            plik = Regex.Replace(plik, "  ", "");
            plik = Regex.Replace(plik, "\r\n", "");
            plik = Regex.Replace(plik, Convert.ToString("'"), Convert.ToString('"'));
            
        }
0

Pamięć zawsze można spróbować zwolnić używając:

GC.Collect();

Ale nie wiadomo jak to zadziała.

Powiedz mi po co jest to:

Convert.ToString('"')
Convert.ToString("'")

Nie prościej użyć odpowiednio:

"\""
"\'"
0

sprobuj dojsc, jaki przyrost zuzycia pamieci powoduja kolejne linijki w changexml. jesli <ort>mniejwiecej </ort>to sie bedzie rozkladalo po rowno i <ort>mniejwiecej </ort>w wielokrotnosciach 6mb, mozliwe ze regexy "po prostu" podczas kolejnych podmian natworzyly tyle lekko rozniacych sie kopii oryginalnego 6mbowego stringa ze glowa boli.. zdziwiloby mnie takie podejscie, ale kto je tam wie.. sprawdz

btw. "plik" jak rozumiem jest typu string?

0

Powiedz mi po co jest to:

Convert.ToString('"')
Convert.ToString("'")

Jako, ze wczesniej bawilem sie innymi znakami, a takze pamiec ludzka jest zawodna, to dlatego tak to teraz wyglada :)
Co do GC.Collect() to niestety, ale nic to nie dalo :(

Natomiast quetzalcoatl napisal:

sprobuj dojsc, jaki przyrost zuzycia pamieci powoduja kolejne linijki w changexml.

Sprawdzilem i niestety, ale kazda linia powieksza o inna wartosc zajecie pamieci.
Mam wrazenie, ze im wiecej jest znajdowanych i poprawianych ciagow znakow, tym mniej pamieci wtedy jest zjadanej.

PS. "plik" oczywiscie jest typu string

Moze macie jakies inne pomysly ?

0
urbiasz napisał(a)

PS. "plik" oczywiscie jest typu string

Tego typu operacje na stringach są raczej bardzo niewydajne. Za każdym kolejnym przypisaniem do zmiennej tego typu tworzy się nowa kopia w pamięci. Ale nie wiem, czy akurat w tym przypadku da się coś z tym zrobić, chyba StringBuilder nie pomoże.

0
urbiasz napisał(a)

Sprawdzilem i niestety, ale kazda linia powieksza o inna wartosc zajecie pamieci.
Mam wrazenie, ze im wiecej jest znajdowanych i poprawianych ciagow znakow, tym mniej pamieci wtedy jest zjadanej.

czyli to by wskazywalo wlasnie na to co podejrzewalem, ze regex tworzy od cholery kopii tymczasowych tego stringa.. pokopie w tym temacie, ale nie mam ostatnio wiele czasu, wiec pare dni moze zejsc

0
quetzalcoatl napisał(a)

czyli to by wskazywalo wlasnie na to co podejrzewalem, ze regex tworzy od cholery kopii tymczasowych tego stringa.. pokopie w tym temacie, ale nie mam ostatnio wiele czasu, wiec pare dni moze zejsc

Wielkie dzieki ! Ja tez szukam jakies info na googlach, ale nie znalazlem <ort>na razie </ort>zadnych informancji :(

0

Take heed and bear witness to the truths that lie herein..

..klasa Regexp przychodzi jako 2-w-1, dwa modele pracy w jednej klasie.

Po pierwsze, mozesz konstruowac sobie obiekty Regexp, podajac im wyrazenia do 'skompilowania', definiujace ich sposob pracy, zapamietac te obiekty, po czym pozniej uzywac ich metod Match/Replace na stringach do przetworzenia.

Po drugie, jak nie chce Ci sie 'bawic' w tworzenie obiektow, mozesz uzyc statycznych metod Match/Replace, pobierajacych string do przetworzenia i string wyrazenia regularnego. Metody te same 'skompiluja' wyrazenie w locie i natychmiast wykonaja swoje zadanie przy jego pomocy.

Tyle pewnie wiedziales.
Ale nie sprawdziles, czym to sie rozni w szczegolach..

Otoz, jak utworzysz sobie obiekt Regexp, no to go masz. Przestaniesz go uzywac - zgubisz go - GC go sprzatnie, i ups, potem musisz sobie stworzyc nowy jak chcesz operacje powtorzyc.

Metody statyczne sa inteligentniejsze. Cache'uja ostatnio wywolane stringi wyrazen i odpowiadajace im Regexp'y, tak zeby nie kompilowac ich niepotrzebnie ponownie tych czesto [czyt: ostatnio] uzywanych.

Po Twoim przypadku widac, ze cacheowanie regexpow nie zawsze wychodzi na dobre.. Najwyrazniej same RegExp'y tez maja jakies cacheowanie wynikow posrednich/koncowych, i te stringi z tymczasowymi wynikami nie mogly zostac sprzatniete przez GC, poniewaz trzymal je obiekt Regexp, trzymany przez cache statycznych metod Regexp'a..

-> albo w tym przypadku przejdz na konstruowanie/uzywanie/niszczenie obiektow RegExp i zapomnij o metodach statycznych. niestety, regexp nie jest IDisposable..

    Regexp rx = new Regex("wyrazenie0"); // zaden z tych obiektow
    rx.Replace...
    rx = new Regex("wyrazenie1"); // nie zostanie scacheowany
    rx.Replace...
    rx = new Regex("wyrazenie2"); // i gc pewnie je posprzata w swoim czasie
    rx.Replace...
    rx = null; // a biorac po uwage rozmiar, pewnie calkiem szybko

-> albo skorzystaj ze statycznego property Regexp.CacheSize [przegapiles je, nazwa dosc znaczaca i pewnie jest opisane na MSDN:)] i w momencie gdy uznasz za stosowne, ustaw je na chwile na zero. Regexp w momencie ustawiania cachesize przycina/powieksza je do odpowiedniego rozmiaru, wiec to powinno wszystko slicznie wymiesc:

    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    int tmp = Regexp.CacheSize; // raczej chcesz potem odtworzyc te wartosc
    Regexp.CacheSize = 0; // teraz cache gubi wszystkie skladowane obiekty Regexp
    GC.Collect(); // mozna, nie trzeba, ale skoro wiadomo ze cos da, to czemu nie?
    Regexp.CacheSize = tmp;

acz radzilbym raczej zrobic cos w stylu:

    int tmp = Regexp.CacheSize; // raczej chcesz potem odtworzyc te wartosc
    Regexp.CacheSize = 0; // niech Regexp przez chwile w ogole nic nie cacheuje, GC bedzie sprzatal takze w trakcie pracy!
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Rexexp.Replace...
    Regexp.CacheSize = tmp;

wtedy w ogole obciazenie pamieci nie powinno urosnac az tak znacznie i nie wywolujesz GC recznie

0

A nie można sobie takiego obiektu Regexa wsadzić w using?

0

No raczej nie bardzo, skoro nie jest IDisposable

0

Wielkie dzieki quetzalcoatl !

Trzeci przyklad jest dla mnie najlepszy!
Pieknie teraz dziala, minimalny przyrost pamieci a po skonczeniu, pamiec wraca do stanu poczatkowego :)

0

Pytanie z innej beczki. Poza @"<id_ms>(.*)</id_ms>" nic nie jest regexem - po co więc zatrudniać kombajn do zerwania mlecza? Nie możesz użyć zwykłego string replece'a?

I mała uwaga do @"<id_ms>(.*)</id_ms>" - nawiasy ostre nie są meta-znakami, nie potrzebny backslash przed nimi.

0 użytkowników online, w tym zalogowanych: 0, gości: 0