Ho cercato di inventare il codice più semplice per riprodurre quello che sto vedendo. Il programma completo è sotto, ma lo descriverò qui. Supponiamo che abbia classe denominata ListData
che ha solo alcune proprietà. Quindi supponiamo di avere una classe MyList
con un membro List<ListData> m_list
. Supponiamo che m_list
venga inizializzato nel costruttore MyList
.Cos'è questo "oggetto pinning handle []" che vedo in Jetbrains dotMemory quando uso un elenco <T>?
Nel metodo principale, creo semplicemente uno di questi oggetti MyList
, aggiungo alcuni ListData
a esso, quindi lo lasciano fuori ambito. Faccio uno snapshot in dotMemory dopo che sono stati aggiunti ListData
, quindi prendo un'altra istantanea dopo che l'oggetto MyList
esce dallo scope.
In dotMemory posso vedere che l'oggetto MyList
è stato recuperato come previsto. Vedo anche che i due oggetti ListData
che ho creato sono stati recuperati come previsto.
Quello che non capisco è perché c'è un ListData[]
che è sopravvissuto? Ecco una schermata di questo: oggetti
ho aperto sopravvissuto sulla più recente snapshot per la ListData[]
allora ho vista chiave di ritenzione Paths, questo è quello che vedo.
Sono nuovo di gestione della memoria NET e ho creato questa applicazione di esempio per aiutarmi a esplorarlo. Ho scaricato la versione di prova di JetBrains dotMemory versione 4.3. Sto usando Visual Studio 2013 Professional. Devo imparare la gestione della memoria in modo da poter risolvere i problemi di memoria che abbiamo al lavoro.
Ecco il programma completo che può essere utilizzato per riprodurre questo. È solo un'app veloce e sporca, ma otterrà la cosa che sto chiedendo se la profilassi.
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();
}
}
}
Passi:
- Costruire sopra il codice nel rilascio.
- In dotMemory, selezionare per creare il profilo di un'app standalone .
- Passare al file di rilascio.
- Selezionare l'opzione per avviare immediatamente la raccolta dei dati di allocazione.
- Fare clic su Esegui.
- Prendere immediatamente un'istantanea e denominarla "prima". Questo è prima che siano aggiunti tutti i dati di lista .
- Nell'app, digitare a e aggiungere due ListData.
- In dotMemory, prendi un'altra istantanea e chiamala "aggiunta 2" perché abbiamo aggiunto due ListData.
- Nell'app, digitare q per uscire (la MyList andrà fuori campo). Prima di digitare nuovamente Invio per uscire dall'app, vai a un'altra istantanea in dotMemory. Chiamarlo "fuori ambito".
- Nell'app, digitare Invio per chiudere l'app.
- In dotMemory, confrontare le istantanee "aggiunte 2" e "fuori ambito" . Raggruppa per spazio dei nomi. Vedrai i ListData [] a cui mi riferisco.
Si noti che MyList e i due oggetti ListData sono stati recuperati dal garbage collector, ma ListData [] no. Perché c'è un ListData [] in giro? Come posso far sì che i rifiuti vengano raccolti?
Yuval, grazie per la risposta. Sto cercando la tua risposta per capire e ti farò sapere se ho delle domande. – cchampion
@cchampion Benvenuto. –
Ok per assicurarmi di aver capito correttamente mi permetta di spiegare con parole mie e per favore correggimi se sbaglio. Quello che sto vedendo è che _emptyArray statico viene lasciato indietro. Poiché _emptyArray è statico, sarà sempre una radice per l'array vuoto e pertanto non verrà mai raccolta la garbage collection. – cchampion