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

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.

fourfour
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:627
n0name_l
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 4 lata
  • Postów:2412
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:

Kopiuj
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.

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:6 dni
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.


edytowany 1x, ostatnio: ŁF
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?

Kopiuj
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?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
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ś?

ŁF
Nie podbijaj wątku.
fourfour
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:627
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?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
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.

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:6 dni
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.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
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ł...

edytowany 1x, ostatnio: somekind
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:

Kopiuj
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.

Kopiuj
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ć...

n0name_l
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 4 lata
  • Postów:2412
0

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

Kopiuj
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.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
0
zaraz_sie_zaloguje napisał(a):

Ta składowa mimo, że jest statyczna:

Kopiuj
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.

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:6 dni
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:

Kopiuj
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.

Kopiuj
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ą?


Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 16 godzin
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.

edytowany 2x, ostatnio: Azarien
0

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

Ostatnie pytanie (mam nadzieję).

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

Kopiuj
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?

fourfour
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:627
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".

fourfour
  • Rejestracja:prawie 11 lat
  • Ostatnio:prawie 9 lat
  • Postów:627
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.

edytowany 1x, ostatnio: fourfour
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 ;)

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:4 dni
  • Lokalizacja:Wrocław
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.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.