zwalnianie niegenerycznych list i garbage collector

0

Cześć,

w jaki sposób mogę zwolnić zasoby?

Obiekty klasy MyData tworzę wielokrotnie w trakcie wykonywania pętli. Wydawało mi się, że po przejściu iteracji pętli wszystkie obiekty są usuwane automatycznie przez garbage collector (skoro są zmiennymi lokalnymi wewnątrz nawiasów klamrowych). Tak jednak nie jest (ponieważ, gdy jest np. powyżej tysięcznej iteracji, aplikacja znacząco zwalnia wykonywanie kolejnych iteracji). Stąd też chciałbym we właściwy sposób zaimplementować zwalnianie zasobów. W jaki sposób mogę to zrobić? (To nie są listy generyczne, więc inne sposoby, których próbowałem, nie powiodły się). Mogę też pokazać kod tego, czego próbowałem, jednak podejrzewam, że niewiele on wniesie nowego do tematu.

public class MyIntegerColumn
{
	public string ParameterName { get; set; }
	public int ParameterValue { get; set; }
	public MyIntegerColumn() { }
	public MyIntegerColumn(string parameterName, int parameterValue)
	{
		ParameterName = parameterName;
		ParameterValue = parameterValue;
	}
}

public class MyData
{
	public List<MyStringColumn> MyStringColumns { get; set; }
	public List<MyDoubleColumn> MyDoubleColumns { get; set; }
	public List<MyDateColumn> MyDateColumns { get; set; }
	public List<MyIntegerColumn> MyIntegerColumns { get; set; }
	public List<MyBooleanColumn> MyBooleanColumns { get; set; }
	public MyData()
	{
		MyStringColumns = new List<MyStringColumn>();
		MyDoubleColumns = new List<MyDoubleColumn>();
		MyDateColumns = new List<MyDateColumn>();
		MyIntegerColumns = new List<MyIntegerColumn>();
		MyBooleanColumns = new List<MyBooleanColumn>();
	}

    ~MyData()
    {
		// ???
	}
	
	public void Dispose()
	{
		// ???
	}
}

Pozdrawiam!

2

W twoim kodzie nie trzeba nic ręcznie zwalniać.

Wydawało mi się, że po przejściu iteracji pętli wszystkie obiekty są usuwane automatycznie przez garbage collector
GC nie działa od razu (tak działają np. obiekty na stosie w C++). GC jest "leniwy": zwolni kiedyś, jak uzna że przyszła na to pora. Czasami dopiero przed zakończeniem działania programu.

Na tym GC polega, by przestać się przejmować pamięcią w 99% przypadków.

Tak jednak nie jest (ponieważ, gdy jest np. powyżej tysięcznej iteracji, aplikacja znacząco zwalnia wykonywanie kolejnych iteracji)
To jest sztuczny przykład, chyba nie chcesz tak robić w prawdziwym programie, prawda?

0

Cześć,

zrobiłem tak, że wyciągnąłem tworzenie zmiennych przed pętlę, ich inicjalizację tam, gdzie do tej pory była deklaracja wraz z inicjalizacją oraz pod sam koniec każdej iteracji przypisuję im wartość null. Niestety, w taki sposób dalej program znacząco spowalnia, gdy ilość iteracji jest zbyt duża, co oznacza, że dalej pamięć nie jest czyszczona we właściwy sposób.

Podejrzewam, że samo przypisanie wartości null nie jest wystarczające. W jaki sposób najłatwiej zadbać o czystą pamięć? Mam dużo różnych typów zmiennych, takich jak: string, string[], List<double>, List<MojaKlasa>, MojaKlasa, IList<System.Reflection.PropertyInfo>, bool.

Dodałem np. mojaLista.Clear() w sekcji, gdzie przypisuję inne wartości do null, jednak otrzymuję wyjątek "Odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu". Mogę poszukać w kodzie i pozbyć się tego wyjątku, jednak tak się zastanawiam, zanim jeszcze coś zrobię: w jaki sposób najłatwiej czyszczenie pamięci z tylu zmiennych pod koniec iteracji zaimplementować?

Pozdrawiam!

1

Ja zwykle implementuje IDisposable (dla "Unmanaged Resources"), do tego używanie using/try-catch-finally. A resztę to już zostawiam woli GC.

0

Pokaż kod, może gdzieś masz leaka.

0

Cześć,

DibbyDum napisał(a):

Ja zwykle implementuje IDisposable (dla "Unmanaged Resources"), do tego używanie using/try-catch-finally. A resztę to już zostawiam woli GC.

W najbliższym czasie przyjrzę się temu IDisposable i spróbuję go zaimplementować dla moich klas (których obiektów używam potem np. w listach).

qwqeassdaz napisał(a):

Pokaż kod, może gdzieś masz leaka.

kod jest raczej długi, za to wyciągnąłem z niego te fragmenty, które podejrzewam, że mogą mieć wpływ na wycieki pamięci. Mam oprócz zmiennych, również listy obiektów moich klas i tablice string[].

foreach (MyData.MyStringColumn currentESC in tmpInputValuesSplit)
System.IO.StreamReader setFileRead = new System.IO.StreamReader(setFile);
setFileRead.Close();

analogicznie

TextWriter tw = new StreamWriter(currentCompFile, true);

próbowałem zadeklarować newEBC przed pętlą, a potem w pętli użyć

newEBC = new MyData.MyBooleanColumn();

zamiast

MyData.MyBooleanColumn newEBC = new MyData.MyBooleanColumn();

później dodać w taki sposób

currentDBRow.MyBooleanColumns.Add(newEBC);

po zmianach (przeniesienie definicji przed pętlę), np. w ten sposób ponownie wykorzystuję zmienne

currentMyDoubleColumn = new MyData.MyDoubleColumn();

Pozdrawiam!

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