2013-02-22 8 views
7

Mam niektóre obiekty, które odczytują plik, zapisują dane w tablicach i wykonują niektóre operacje. Sekwencja to Utwórz obiekt A, operuj z obiektem A. Utwórz obiekt B, operuj obiektem B ... Dane odczytywane przez każdy obiekt mogą wynosić około 10 MB. Najlepszym rozwiązaniem byłoby usunięcie każdego obiektu po pracy z każdym z nich. Powiedzmy, że chcę, aby mój program przeznaczyć około 10 MB pamięci, a nie 10MB * 1000 Objects 1GBKonieczność usuwania obiektów: implementacja Usunąć lub utworzyć obiekty w funkcji?

Obiekty są czymś jak:

class MyClass 
{ 
    List<string[]> data; 

    public MyClass(string datafile) 
    { 
     using (CsvReader csv = new CsvReader(new StreamReader(datafile), true)) 
     { 
      data = csv.ToList<string[]>(); 
     } 
    } 

    public List<string> Operate() 
    { 
    ... 
    } 

} 

Moje pytanie brzmi: należy wdrożyć wyrzucać? I zrobić coś takiego:

List<string> results = new List<results>(); 

using (MyClass m = new MyClass("fileM.txt")) 
      { 
       results.AddRange(m.Operate()); 
      } 

using (MyClass d = new MyClass("fileD.txt")) 
      { 
       results.AddRange(d.Operate()); 
      } 

... 

Ive przeczytać, że wdrożenie Jednorazowe jest zalecane podczas korzystania z zasobów unmmanaged (gniazda, strumienie, ...), ale w mojej klasie mam tylko dużych tablic danych.

Innym sposobem byłoby stworzenie funkcji dla poszczególnych obiektów (przypuszczam GC usunie obiekt utworzony w funkcję automatycznie):

List<string> results = new List<results>(); 
results.AddRange(myFunction("fileM.txt")); 
results.AddRange(myFunction("fileD.txt")); 


public List<string> myFunction(string file) 
{ 
MyClass c = new MyClass(file); 
return results.AddRange(c.Operate()); 
} 
+0

Edytowałem twój tytuł. Zobacz, "[Czy w tytułach pytania powinny znaleźć się" znaczniki "?] (Http://meta.stackexchange.com/questions/19190/)", gdzie konsensus brzmi "nie, nie powinien". –

Odpowiedz

5

IDisposable etc nie pomoże tutaj, ponieważ nie powoduje wszystko, co można zebrać. W tego typu scenariuszu najlepszym sposobem jest użycie puli w celu zmniejszenia alokacji - w istocie staje się on swoim własnym menedżerem pamięci. Na przykład, jeśli Twój List<string> jest duży, możesz uniknąć wielu tablic, ponownie korzystając z list - oczywiście po ich wyczyszczeniu. Jeśli wywołasz .Clear(), tablica podkładowa nie jest resetowana - ustawia tylko znacznik logiczny, który traktuje go jako pusty. W twoim konkretnym przypadku wiele twoich obiektów będzie indywidualnymi string s; to jest trudniejsze, ale przynajmniej są małe i powinny być zbierane w zero generacji.

+1

Jeśli chcesz zmienić rozmiar tablicy, możesz ustawić "Capacity = someValue" po wywołaniu 'Clear()'. (Zauważ, że nie pozwoli ci to zmniejszyć "Pojemność" poniżej bieżącego rozmiaru, więc musisz go najpierw wyczyścić.) – porges

+0

Ponowne użycie listy jest dobrym pomysłem, chociaż w moim przypadku jest skomplikowane. Czytam dane z niektórych plików CSV. Dla każdego pliku CSV wyodrębniam kolumny danych (lista łańcuchów dla każdej kolumny) i utworzę kilka wykresów. Ponowne wykorzystanie listy danych odczytanych dla każdego pliku CSV jest łatwe do wdrożenia. Ale ponowne zestawienie list kolumn każdego pliku CSV jest bardziej skomplikowane. Jeden plik csv może mieć 3 kolumny (3 listy), a także 8 kolumn (8 list), więc musiałem utworzyć tyle list co maksymalna liczba kolumn, jakie może mieć csv. A następnie przywróć każdą listę dla każdej kolumny ... złożony kod. Łatwiej byłoby usunąć każdy obiekt ze swoimi kolumnami :) – Alberto

3

W twoim przypadku przydzielę pojedynczą tablicę buforową. Na przykład przydzielić tablicę o wielkości 10 MB i wypełnić ją żądanymi danymi. Następnie, kiedy dojdziesz do następnego obiektu, po prostu użyj tablicy ponownie. Jeśli kiedykolwiek potrzebujesz większej tablicy, możesz po prostu przydzielić nową, większą tablicę i użyć jej zamiast niej. Śmieciarz w końcu usunie mniejszy.

Możesz także użyć List<T>, zrobi to wewnętrznie (przydziel tablicę, zachowaj ją, aż stanie się zbyt mała, przydziel nową). Po prostu Clear to przed utworzeniem następnego obiektu.

Należy pamiętać, że użytkownik nie może wymusić odśmiecacza w celu zebrania obiektu. IDisposable jest rzeczywiście używany tylko do czyszczenia niezarządzanych zasobów, ponieważ śmieciarz nie wie o nich ani nie zamyka uchwytów (plików). Wywołanie Dispose nie gwarantuje (lub sugeruje), że obiekt został usunięty z pamięci.

Jeśli jednak nic nie zmienisz, kod będzie nadal poprawny i będzie działał prawidłowo. Śmieciarz jest odpowiedzialny za usuwanie nieużywanych obiektów, kiedy tylko ma na to ochotę, i zapewnia, że ​​w każdej chwili jest dostępna duża ilość pamięci. Jedyne, co musisz zrobić, aby kolekcjoner wykonał swoją pracę, to odrzucić wszelkie odniesienia do starych obiektów (poprzez nadpisanie ich lub ustawienie ich na null lub wypuszczenie ich poza zakres).

) Możesz wymusić odśmiecenie śmieci, aby odebrać dane, dzwoniąc pod numer GC.Collect().Jednak jest to zalecane , a nie. Niech sam wyrzuci śmieciarz.

0

Jeśli używasz .NET 4.0 lub nowszego, spójrz na klasę BlockingCollection. Opcja constructor that takes the Int32 parameter umożliwia określenie górnej granicy rozmiaru kolekcji. Metody Add i Take działają jako przepustnice. Dodanie zakończy się sukcesem tylko wtedy, gdy nie zostanie osiągnięta górna granica. Jeśli tak, to zablokuje. Podjęcie powiedzie się tylko, jeśli przedmiot istnieje. Jeśli żaden przedmiot nie istnieje, zostanie zablokowany, dopóki nie będzie dostępny. Oczywiście, klasa ma pewne odmiany tych metod, więc w pełni zbadaj dokumentację, aby zobaczyć, które, jeśli w ogóle, mają sens.

Powiązane problemy