Narastające użycie pamięci w C#

0

Witam,
Piszę pewną aplikację w C#.NET i zauważam, że zużycie pamięci wraz z działaniem programu wciąż rośnie.

Wiem, że w C# jest Garbage Collector i on powinien sprzątać nieużywane obiekty.

Kolega mi powiedział, że muszę gdzieś wciąż tworzyć nowe obiekty, a pozostają mi referencje do starych obiektów i GC ich nie usuwa.

Tylko jak to zlokalizować i poprawić?

Pozdrawiam.

0

http://memprofiler.com/ [Nie testowane]

Ale jak juz to szukaj mniej-wiecej tymi samymi keywordami :)

0

No poszukam jakiegoś profilera, bo ręcznie tego nie znajdę...

0

Znalazłem w moim projekcie kod podobny do tego:

public static class MyClass
{
    public static List<Something> listOfSomethings = new List<Something>();
    public static Something st;
}

//...

public static void CreateSomething()
{
    var something = new Something();
    MyClass.listOfSomethings.Add(something);

    MyClass.st = new Something();
}

Byłem zmuszony zrobić to statycznie i nie wiem czy takie rozwijązanie nie powoduje jakichś wycieków pamięci.

2

Żaden obiekt, dodany do czegoś takiego, nie będzie usuwany z pamięci. Żaden obiekt, zawarty w obiekcie dodanym do takiej listy, nie będzie usuwany z pamięci, i tak dalej, i tak dalej.

PS. Chyba, że implementuje IDisposable, a .Dispose() zostanie wywołane "ręcznie" - jest wtedy szansa, że część zasobów takiego obiektu zostanie zwolniona. Każdy obiekt trzeba z takiej listy usunąć albo ustawić referencję do takiego obiektu na null.

0
ŁF napisał(a):

Żaden obiekt, dodany do czegoś takiego, nie będzie usuwany z pamięci. Żaden obiekt, zawarty w obiekcie dodanym do takiej listy, nie będzie usuwany z pamięci, i tak dalej, i tak dalej.

Dzięki za ten post, pewnie tu jest ten wyciek. Mógłbyś odpowiedzieć mi na pytania w komentarzach do kodu poniżej?

public static class MyClass
{
    public static List<Something> listOfSomethings = new List<Something>();
    public static Something st;
}
 
//...
 
public static void CreateSomething()
{
    var something = new Something();

    MyClass.listOfSomethings.Add(something);

    //czy po utworzeniu nowej listy jak poniżej,
    //obiekty poprzedniej listy zostaną usunięte?
    MyClass.listOfSomethings = new List<Something>();
 
    MyClass.st = new Something();

    //czy poprzednie Something zostanie usunięte po przypisaniu nowego?
    MyClass.st = new Something();
}

Jeśli te obiekty o które pytam powyżej nie zostają usuwane to jak je usunąć? Nie używać static?

1

A czemu w ogóle używasz static?

0
somekind napisał(a):

A czemu w ogóle używasz static?

Żeby mieć dostęp do klasy czy składowej z całego programu.

0

Odpowie ktoś na te pytania w komentarzach do kodu? @ŁF jesteś?

0
zaraz_sie_zaloguje napisał(a):

Odpowie ktoś na te pytania w komentarzach do kodu? @ŁF jesteś?

ŁF napisał(a):

Żaden obiekt, dodany do czegoś takiego, nie będzie usuwany z pamięci. Żaden obiekt, zawarty w obiekcie dodanym do takiej listy, nie będzie usuwany z pamięci, i tak dalej, i tak dalej.

PS. Chyba, że implementuje IDisposable, a .Dispose() zostanie wywołane "ręcznie" - jest wtedy szansa, że część zasobów takiego obiektu zostanie zwolniona. Każdy obiekt trzeba z takiej listy usunąć albo ustawić referencję do takiego obiektu na null.

0
fourfour napisał(a):
ŁF napisał(a):

Żaden obiekt, dodany do czegoś takiego

Jakiego "czegoś takiego"? Składowej, listy, klasy?

0
zaraz_sie_zaloguje napisał(a):

Żeby mieć dostęp do klasy czy składowej z całego programu.

Ale po co? Klasa powinna być dostępna tylko tam, gdzie jest potrzebna, a nie wszędzie.

0
somekind napisał(a):
zaraz_sie_zaloguje napisał(a):

Żeby mieć dostęp do klasy czy składowej z całego programu.

Ale po co? Klasa powinna być dostępna tylko tam, gdzie jest potrzebna, a nie wszędzie.

Klasa przechowuje rzeczy ogólne, główne, wspólne dla całego programu. Jedna strona zapisuje coś w tej klasie, inne odczytują itp.

0
zaraz_sie_zaloguje napisał(a):

Jakiego "czegoś takiego"? Składowej, listy, klasy?

Obiektu statycznego GC nie może sam usunąć (może to zrobić dopiero po usunięciu obiektu z poziom kodu, czyli coś w stylu Sth StatycznyObiekt = null czy = new Sth()). Siłą rzeczy nie może usunąć obiektów, do których obiekt statyczny trzyma referencje, ani obiektów, do których referencje są trzymane w obiektach, do których obiekt statyczny trzyma referencje - itp, itd.

0
ŁF napisał(a):
zaraz_sie_zaloguje napisał(a):

Jakiego "czegoś takiego"? Składowej, listy, klasy?

Obiektu statycznego GC nie może sam usunąć (może to zrobić dopiero po usunięciu obiektu z poziom kodu, czyli coś w stylu Sth StatycznyObiekt = null czy = new Sth()). Siłą rzeczy nie może usunąć obiektów, do których obiekt statyczny trzyma referencje, ani obiektów, do których referencje są trzymane w obiektach, do których obiekt statyczny trzyma referencje - itp, itd.

No dobra, czyli obiekt statyczny sobie istnieje i tyle. A mi zużycie pamięci rośnie. Tak jakby coś nie było zwalniane.

0
zaraz_sie_zaloguje napisał(a):

Klasa przechowuje rzeczy ogólne, główne, wspólne dla całego programu. Jedna strona zapisuje coś w tej klasie, inne odczytują itp.

Co oznacza, że powinieneś przeprojektować swój program. Globalna statyczna klasa to nie jest sposób na przekazywanie danych między innymi klasami. Zapoznaj się ze słowem kluczowym return.

zaraz_sie_zaloguje napisał(a):

No dobra, czyli obiekt statyczny sobie istnieje i tyle. A mi zużycie pamięci rośnie. Tak jakby coś nie było zwalniane.

No nie jest zwalniane, bo jest statyczne, @ŁF to chyba cztery razy powtórzył...

0
somekind napisał(a):
zaraz_sie_zaloguje napisał(a):

No dobra, czyli obiekt statyczny sobie istnieje i tyle. A mi zużycie pamięci rośnie. Tak jakby coś nie było zwalniane.

No nie jest zwalniane, bo jest statyczne, @ŁF to chyba cztery razy powtórzył...

Wiem, że nie jest zwalniane, bo jest statyczne, ale dlaczego zużycie pamięci ciągle rośnie.

Ta składowa mimo, że jest statyczna:

static public Something sth;

zawsze będzie miała rozmiar Something, więc zużycie pamięci nie powinno rosnąć.

Czy chcecie powiedzieć, że to co przypisuję do statycznej składowej nie jest usuwane?
Np.

static public Something sth;
sth = new Something();
sth = new Something();
sth = new Something();

Czy powyższy kod powoduje, że w pamięci powstają trzy obiekty something? Czy dwa są usuwane z zostaje ostatni (jak jedno Something nadpisuje drugie to do tamtego nie ma już referencji).

Coś nie mogę Was zrozumieć...

0

Wszystko bedzie z czasem usuniete do czego nie masz referencji.
Jesli robisz:

static Something sth;
sth = new Something()
sth = new Something() // = null

To ten pierwszy Something sobie kiedys zniknie.

Ale.. nikt nie wie czy to w tym miejscu masz problem z pamiecia. Po prostu uzyj profilera zamiast na slepo czas marnowac.

0
zaraz_sie_zaloguje napisał(a):

Ta składowa mimo, że jest statyczna:

static public Something sth;

zawsze będzie miała rozmiar Something, więc zużycie pamięci nie powinno rosnąć.

Jeśli rozbudowujesz graf obiektów, którego korzeniem jest zmienna sth, to zużycie pamięci wzrośnie, a to prawdopodobnie właśnie robisz.

0
zaraz_sie_zaloguje napisał(a):
somekind napisał(a):
zaraz_sie_zaloguje napisał(a):

No dobra, czyli obiekt statyczny sobie istnieje i tyle. A mi zużycie pamięci rośnie. Tak jakby coś nie było zwalniane.

No nie jest zwalniane, bo jest statyczne, @ŁF to chyba cztery razy powtórzył...

Wiem, że nie jest zwalniane, bo jest statyczne, ale dlaczego zużycie pamięci ciągle rośnie.

Masz problemy z czytaniem ze zrozumieniem. Nie jest zwalniane, bo jest statyczne i - prawdopodobnie - dlatego zużycie pamięci rośnie.

zaraz_sie_zaloguje napisał(a):

Ta składowa mimo, że jest statyczna:

static public Something sth;

zawsze będzie miała rozmiar Something, więc zużycie pamięci nie powinno rosnąć.

Zauważ, że masz DWIE zmienne statyczne, pierwsza jest listą i o ile jej rozmiar nie będzie znacznie rosnąć, bo tylko trzyma referencje, o tyle przyczepione do niej obiekty (i całe drzewko siedzących w tych obiektach dalszych obiektów) będą siedzieć w pamięci tak długo, aż z tej listy nie zostaną usunięte.

zaraz_sie_zaloguje napisał(a):

Czy chcecie powiedzieć, że to co przypisuję do statycznej składowej nie jest usuwane?
Np.

static public Something sth;
sth = new Something();
sth = new Something();
sth = new Something();

Czy powyższy kod powoduje, że w pamięci powstają trzy obiekty something? Czy dwa są usuwane z zostaje ostatni (jak jedno Something nadpisuje drugie to do tamtego nie ma już referencji).

Chcemy powiedzieć, że czytasz bez zrozumienia. Zgaduję, że to przez to, że brakuje Ci podstaw programowania obiektowego. W pamięci powstaną trzy obiekty (chyba, że kompilator to zoptymalizuje, ale nie sądzę), dwa po jakimś czasie zostaną zwolnione, bo referencja do nich ginie, trzeci będzie wisiał. Wiesz, co to jest referencja do obiektu? Rozumiesz, jak działa GC? Rozumiesz różnice pomiędzy zmienną statyczną a niestatyczną?

0

jak jedno Something nadpisuje drugie to do tamtego nie ma już referencji

Obiekt, do którego nie ma referencji może zostać zniszczony i usunięty z pamięci.
Nie od razu i nie bardzo wiadomo kiedy — ale najpóźniej w momencie wyjścia z programu.

Obiekt, do którego referencja jest trzymana gdzieś w statycznej tablicy (i referencja do tej tablicy istnieje) nie zostanie zniszczony póki program działa.

Jeśli zgubiona zostanie każda referencja do tej tablicy (nadpisana nullem, albo referencją na inną tablicę) to tablica może zostać usunięta. Powoduje to utratę referencji na obiekty zawarte w tablicy, i jeśli do danego obiektu była to jedyna czy ostatnia referencja, to taki obiekt może zostać zniszczony. I tak dalej.

Dotnetowy GC jest odporny na problem referencji cyklicznych: czyli jeśli obiekt A wskazuje na B, a B na A, ale zarówno A jak i B zostają zgubione, to oba te obiekty mogą zostać usunięte przez GC, mimo że istnieje referencja na A i istnieje referencja na B.

0

Dziękuję serdecznie, trochę mi się rozjaśniło :)

Ostatnie pytanie (mam nadzieję).

Załóżmy, że mamy taki kod:

public class Class1
{
    public List<string> list1;
}

static public class Class2
{
    static public List<Class1> listOfClass1;
}

(...)
Class1.list1 = new List<string>();
Class1.list1.Add("test");
Class2.listOfClass1 = new List<Class1>();
Class2.listOfClass1.Add(new Class1());

Class2.listOfClass1 = null;

Czy w takim kodzie GC może usunąć z pamięci listę list1, obiekty klasy Class1 i listę listOfClass1?

0

A jak myślisz, i dlaczego tak myślisz?

0
fourfour napisał(a):

A jak myślisz, i dlaczego tak myślisz?

Mam dwie wersje.

Lista list1, obiekty klasy Class1 i lista listOfClass1 są usuwane, bo przypisanie null do listOfClass1 spowoduje, że nie ma referencji do listy.

Nie wszystko jest usuwane, bo jest przypisanie null do listOfClass1, ale obiekt Class1 zawiera listę list1, która ma referencje do stringa.

Więc nie wiem, czy przypisanie nulla lub nowej referencji sprawia, że wszystko "zagnieżdżone" ginie, czy tak jak w C++ trzeba stopniowo wszystko "likwidować - od potomków do rodzica".

0
zaraz_sie_zaloguje napisał(a):
fourfour napisał(a):

A jak myślisz, i dlaczego tak myślisz?

Więc nie wiem, czy przypisanie nulla lub nowej referencji sprawia, że wszystko "zagnieżdżone" ginie, czy tak jak w C++ trzeba stopniowo wszystko "likwidować - od potomków do rodzica".

Odpowiedzi:

ŁF napisał(a):

Obiektu statycznego GC nie może sam usunąć (może to zrobić dopiero po usunięciu obiektu z poziom kodu, czyli coś w stylu Sth StatycznyObiekt = null czy = new Sth()). Siłą rzeczy nie może usunąć obiektów, do których obiekt statyczny trzyma referencje, ani obiektów, do których referencje są trzymane w obiektach, do których obiekt statyczny trzyma referencje - itp, itd.

somekind napisał(a):

Jeśli rozbudowujesz graf obiektów, którego korzeniem jest zmienna sth, to zużycie pamięci wzrośnie, a to prawdopodobnie właśnie robisz.

Azarien napisał(a):

Obiekt, do którego nie ma referencji może zostać zniszczony i usunięty z pamięci.
Nie od razu i nie bardzo wiadomo kiedy — ale najpóźniej w momencie wyjścia z programu.

Obiekt, do którego referencja jest trzymana gdzieś w statycznej tablicy (i referencja do tej tablicy istnieje) nie zostanie zniszczony póki program działa.

Jeśli zgubiona zostanie każda referencja do tej tablicy (nadpisana nullem, albo referencją na inną tablicę) to tablica może zostać usunięta. Powoduje to utratę referencji na obiekty zawarte w tablicy, i jeśli do danego obiektu była to jedyna czy ostatnia referencja, to taki obiekt może zostać zniszczony. I tak dalej.

0

@fourfour - dziękuję za wklejanie kolejny raz tego samego.

Ktoś nie rozumie to się próbuje wytłumaczyć jakoś innymi słowami, obrazowo.

Jak dziecko zapyta co to jest krowa, a Ty powiesz: "Takie zwierze."

A dziecko dalej: "Ale no co to jest".

A Ty mu będziesz powtarzał: "Takie zwierze. Takie zwierze."

Więcej razy powtórzysz to myślisz, że zrozumie? Co najwyżej zapamieta ;)

0
zaraz_sie_zaloguje napisał(a):

Czy w takim kodzie GC może usunąć z pamięci listę list1, obiekty klasy Class1 i listę listOfClass1?

Ponieważ przypisałeś null do tej zmiennej, to graf obiektów który wskazywała przestaje być gdziekolwiek wykorzystywany, więc obszar pamięci, na który wskazywała wcześniej może zostać zwolniony.

zaraz_sie_zaloguje napisał(a):

Więcej razy powtórzysz to myślisz, że zrozumie? Co najwyżej zapamieta ;)

Trzy razy już dostałeś odpowiedź, że krowa ma łaty, rogi, ogon i cycki.

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