2015-07-06 7 views
8

Próbowałem wymyślić najprostszy kod, aby odtworzyć to, co widzę. Pełny program znajduje się poniżej, ale opiszę to tutaj. Załóżmy, że mam klasę o nazwie ListData, która ma tylko niektóre właściwości. Załóżmy, że mam klasę MyList, która ma członka List<ListData> m_list. Załóżmy, że m_list zostanie zainicjowany w konstruktorze MyList.Co to jest "obiekt uchwytów do przypinania []", który widzę w pamięci dot-Speory Jetbrains, gdy używam Listy <T>?

W głównej metodzie po prostu utworzę jeden z tych obiektów MyList, dodam do niego kilka ListData, a następnie pozwól mu wyjść poza zakres. Biorę migawkę w dotMemory po dodaniu ListData, a następnie robię kolejną migawkę po tym, jak obiekt MyList wychodzi poza zakres.

W dotMemory widzę, że obiekt MyList został odzyskany zgodnie z oczekiwaniami. Widzę również, że dwa utworzone obiekty ListData również zostały odzyskane zgodnie z oczekiwaniami.

Czego nie rozumiem, dlaczego przetrwało ListData[]? Oto zrzut ekranu z tego: Screenshot of this in dotMemory

otworzę przetrwały obiekty na najnowszej migawki do ListData[] potem zobaczyć Kluczowe retencji ścieżek, jest to, co widzę.

Key Retention Paths

Jestem nowy w zarządzaniu pamięcią .NET i ja stworzyliśmy przykładową aplikację, aby pomóc mi go zbadać. Pobrałem wersję próbną JetBrains dotMemory w wersji 4.3. Korzystam z programu Visual Studio 2013 Professional. Muszę nauczyć się zarządzania pamięcią, aby naprawić problemy z pamięcią, które mamy w pracy.

Oto pełny program, który może zostać użyty do odtworzenia tego. Jest to po prostu szybka i brudna aplikacja, ale dostanie to, o co pytam, jeśli to zrobisz.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication1 
{ 

    class ListData 
    { 
     public ListData(string name, int n) { Name = name; Num = n; } 
     public string Name { get; private set; } 
     public int Num { get; private set; } 
    } 

    class MyList 
    { 

     public MyList() 
     { 
      m = new List<ListData>(); 
     } 

     public void AddString(ListData d) 
     { 
      m.Add(d); 
     } 

     private List<ListData> m; 

    } 


    class Program 
    { 
     static void Main(string[] args) 
     { 
      { 
       MyList l = new MyList(); 
       bool bRunning = true; 
       while (bRunning) 
       { 
        Console.WriteLine("a or q"); 
        string input = Console.ReadLine(); 
        switch (input) 
        { 
         case "a": 
          { 
           Console.WriteLine("Name: "); 
           string strName = Console.ReadLine(); 
           Console.WriteLine("Num: "); 
           string strNum = Console.ReadLine(); 
           l.AddString(new ListData(strName, Convert.ToInt32(strNum))); 
           break; 
          } 
         case "q": 
          { 
           bRunning = false; 
           break; 
          } 
        } 
       } 
      } 

      Console.WriteLine("good bye"); 
      Console.ReadLine(); 
     } 
    } 
} 

Kroki:

  1. Budowa Powyższy kod uwalnianie.
  2. W dotMemory wybierz profil autonomicznej aplikacji .
  3. Przejdź do wydania exe.
  4. Wybierz opcję natychmiastowego rozpoczęcia zbierania danych o przydziałach.
  5. Kliknij Uruchom.
  6. Zrób natychmiast migawkę i nadaj jej nazwę "przed". To jest przed dodaniem jakichkolwiek listData .
  7. W aplikacji wpisz a i dodaj dwie listy danych.
  8. W dotMemory, zrób kolejną migawkę i nadaj jej nazwę "added 2", ponieważ my dodaliśmy dwie listy danych.
  9. W aplikacji wpisz q, aby zakończyć (lista MyList zniknie z zakresu). Przed wpisaniem Enter ponownie, aby wyjść z aplikacji, zrób kolejną migawkę w dotMemory. Nazwij go "poza zakresem".
  10. W aplikacji wpisz Enter, aby zamknąć aplikację.
  11. W dotMemory porównaj migawki "dodano 2" i "poza zakresem" . Grupuj według przestrzeni nazw. Zobaczysz ListData [], które mam na myśli.

Zauważ, że obiekty MyList i dwa obiekty ListData zostały zbuforowane, ale ListData [] nie. Dlaczego kręci się ListData []? Jak mogę sprawić, że zostaną zebrane śmieci?

Odpowiedz

3

Dlaczego w witrynie kręci się lista? Jak mogę sprawić, że zostanie pobrane śmieci?

Jeśli spojrzeć na „tworzenie ślad stosu” wewnątrz dotMemory, zobaczysz:

dotMemory StackTrace

To pokazuje, że pusta ListData[0] instancja została stworzona przez statycznym konstruktorze List<T>. If you look at the source, zobaczysz to:

static readonly T[] _emptyArray = new T[0];  

List<T> inicjuje domyślny, pustą tablicę w celu optymalizacji uniknąć takiej alokacji za każdym razem tworzyć nowy List<T>. Jest to domyślny konstruktor:

public List() 
{ 
    _items = _emptyArray; 
} 

Tylko jedna używasz List<T>.Add, będzie to rozmiar tablicy.

static członków są przywoływane z "High Frequency Heap", które są tworzone raz dla każdego AppDomain w aplikacji. Przypięty object[], który widzisz, jest w rzeczywistości miejscem, w którym przechowywane są wszystkie instancje static.

Ponieważ instancja to static, pozostanie w pamięci przez cały okres użytkowania aplikacji.

+0

Yuval, dziękuję za odpowiedź. Rozglądam się nad twoją odpowiedzią, aby zrozumieć, a dam ci znać, jeśli mam pytania. – cchampion

+0

@cchampion Zapraszamy. –

+0

Ok, aby upewnić się, że rozumiem poprawnie, pozwól mi wyjaśnić własnymi słowami i popraw mnie, jeśli się mylę. To, co widzę, to to, że statyczne _emptyArray pozostało w tyle. Ponieważ _emptyArray jest statyczny, zawsze będzie korzeniem pustej tablicy i dlatego nigdy nie będzie zbierać śmieci. – cchampion