Domanda

Ho scritto C ++ per 10 anni. Ho riscontrato problemi di memoria, ma potrebbero essere risolti con un ragionevole sforzo.

Negli ultimi due anni ho scritto C #. Trovo di avere ancora molti problemi di memoria. Sono difficili da diagnosticare e risolvere a causa della non determinanza e perché la filosofia C # è che non dovresti preoccuparti di queste cose quando lo fai decisamente.

Un problema particolare che riscontro è che devo smaltire e ripulire esplicitamente tutto nel codice. In caso contrario, i profiler della memoria non aiutano davvero perché c'è così tanta pula che fluttua attorno a te che non riesci a trovare una perdita tra tutti i dati che stanno cercando di mostrarti. Mi chiedo se ho un'idea sbagliata o se lo strumento che ho non è il migliore.

Quali tipi di strategie e strumenti sono utili per affrontare le perdite di memoria in .NET?

È stato utile?

Soluzione

Uso Scitech MemProfiler quando sospetto una perdita di memoria.

Finora l'ho trovato molto affidabile e potente. Mi ha salvato la pancetta in almeno un'occasione.

Il GC funziona molto bene in .NET IMO, ma proprio come qualsiasi altra lingua o piattaforma, se si scrive codice errato, possono succedere cose brutte.

Altri suggerimenti

Solo per il problema dell'oblio da smaltire, prova il soluzione descritta in questo post di blog . Ecco l'essenza:

    public void Dispose ()
    {
        // Dispose logic here ...

        // It's a bad error if someone forgets to call Dispose,
        // so in Debug builds, we put a finalizer in to detect
        // the error. If Dispose is called, we suppress the
        // finalizer.
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

#if DEBUG
    ~TimedLock()
    {
        // If this finalizer runs, someone somewhere failed to
        // call Dispose, which means we've failed to leave
        // a monitor!
        System.Diagnostics.Debug.Fail("Undisposed lock");
    }
#endif

Abbiamo utilizzato Ants Profiler Pro dal software Red Gate in il nostro progetto. Funziona davvero bene per tutte le applicazioni basate sul linguaggio .NET.

Abbiamo scoperto che .NET Garbage Collector è molto "sicuro". nella sua pulizia di oggetti in memoria (come dovrebbe essere). Manterrebbe gli oggetti in giro solo perché potremmo usarli in futuro. Ciò significava che dovevamo stare più attenti al numero di oggetti che abbiamo gonfiato in memoria. Alla fine, abbiamo convertito tutti i nostri oggetti dati in un "infllate on-demand" (poco prima che sia richiesto un campo) per ridurre il sovraccarico di memoria e aumentare le prestazioni.

MODIFICA: ecco un'ulteriore spiegazione di cosa intendo per "gonfiare su richiesta". Nel nostro modello a oggetti del nostro database utilizziamo Proprietà di un oggetto padre per esporre gli oggetti figlio. Ad esempio, se avessimo un record che faceva riferimento ad altri "dettagli" o " ricerca " registrare su base individuale lo struttureremmo in questo modo:

class ParentObject
   Private mRelatedObject as New CRelatedObject
   public Readonly property RelatedObject() as CRelatedObject
      get
         mRelatedObject.getWithID(RelatedObjectID)
         return mRelatedObject
      end get
   end property
End class

Abbiamo scoperto che il sistema sopra ha creato alcuni problemi di memoria e prestazioni reali quando c'erano molti record in memoria. Quindi siamo passati a un sistema in cui gli oggetti venivano gonfiati solo quando venivano richiesti e le chiamate al database venivano eseguite solo quando necessario:

class ParentObject
   Private mRelatedObject as CRelatedObject
   Public ReadOnly Property RelatedObject() as CRelatedObject
      Get
         If mRelatedObject is Nothing
            mRelatedObject = New CRelatedObject
         End If
         If mRelatedObject.isEmptyObject
            mRelatedObject.getWithID(RelatedObjectID)
         End If
         return mRelatedObject
      end get
   end Property
end class

Questo si è rivelato molto più efficiente perché gli oggetti sono stati tenuti fuori dalla memoria fino a quando non sono stati necessari (è stato effettuato l'accesso al metodo Get). Ha fornito un notevole incremento delle prestazioni nel limitare gli accessi al database e un enorme guadagno nello spazio di memoria

Devi ancora preoccuparti della memoria quando scrivi un codice gestito a meno che la tua applicazione non sia banale. Suggerirò due cose: innanzitutto, leggi CLR via C # perché ti aiuterà a capire la gestione della memoria in .NET. In secondo luogo, impara a utilizzare uno strumento come CLRProfiler (Microsoft). Questo può darti un'idea di ciò che sta causando la tua perdita di memoria (ad es. Puoi dare un'occhiata alla frammentazione dell'heap di oggetti di grandi dimensioni)

Stai usando un codice non gestito? Se non si utilizza codice non gestito, secondo Microsoft, le perdite di memoria in senso tradizionale non sono possibili.

Tuttavia, la memoria utilizzata da un'applicazione potrebbe non essere rilasciata, pertanto l'allocazione della memoria di un'applicazione potrebbe aumentare per tutta la durata dell'applicazione.

  

Da Come identificare le perdite di memoria nel Common Language Runtime su Microsoft.com

     

In .NET può verificarsi una perdita di memoria   Applicazione quadro quando si utilizza   codice non gestito come parte del   applicazione. Questo codice non gestito può   perdita di memoria e .NET Framework   il runtime non può risolvere questo problema.

     

Inoltre, un progetto può solo   sembra avere una perdita di memoria. Questo   condizione può verificarsi se molti di grandi dimensioni   oggetti (come oggetti DataTable)   vengono dichiarati e quindi aggiunti a   raccolta (come un DataSet). Il   risorse che possiedono questi oggetti   non essere mai rilasciato e le risorse   vengono lasciati vivi per l'intera durata di   il programma. Questo sembra essere un   perdita, ma in realtà è solo un   sintomo di come è la memoria   essere assegnato al programma.

Per gestire questo tipo di problema, è possibile implementare IDisposable. Se vuoi vedere alcune delle strategie per gestire la gestione della memoria, suggerirei di cercare IDisposable, XNA, gestione della memoria poiché gli sviluppatori di giochi devono avere una garbage collection più prevedibile e quindi costringere il GC a fare la sua cosa.

Un errore comune è quello di non rimuovere i gestori di eventi che si iscrivono a un oggetto. Una sottoscrizione del gestore eventi impedisce il riciclo di un oggetto. Inoltre, dai un'occhiata alla using che ti consente di creare un ambito limitato per la vita di una risorsa.

Questo blog ha alcune fantastiche procedure dettagliate che utilizzano windbg e altri strumenti per rintracciare perdite di memoria di tutti i tipi. Ottima lettura per sviluppare le tue abilità.

Ho appena avuto una perdita di memoria in un servizio Windows, che ho risolto.

Innanzitutto, ho provato MemProfiler . Ho trovato davvero difficile da usare e per niente user friendly.

Quindi, ho usato JustTrace che è più facile da usare e offre maggiori dettagli sugli oggetti che non sono disposti correttamente.

Mi ha permesso di risolvere la perdita di memoria molto facilmente.

Se le perdite che stai osservando sono dovute a un'implementazione della cache in fuga, questo è uno scenario in cui potresti voler considerare l'uso di WeakReference. Ciò potrebbe aiutare a garantire che la memoria venga rilasciata quando necessario.

Tuttavia, IMHO sarebbe meglio prendere in considerazione una soluzione su misura - solo tu sai davvero per quanto tempo devi tenere gli oggetti in giro, quindi progettare un codice di pulizia adeguato per la tua situazione di solito è l'approccio migliore.

Big guns - Debugging Strumenti per Windows

Questa è una straordinaria raccolta di strumenti. Puoi analizzare sia heap gestiti che non gestiti con esso e puoi farlo offline. Questo è stato molto utile per il debug di una delle nostre applicazioni ASP.NET che ha continuato a riciclare a causa di un uso eccessivo della memoria. Ho dovuto solo creare un dump della memoria completa del processo di vita in esecuzione sul server di produzione, tutte le analisi sono state eseguite offline in WinDbg. (Si è scoperto che alcuni sviluppatori stavano abusando dell'archiviazione di sessioni in memoria.)

" Se rotto è ... " il blog è molto utile articoli sull'argomento.

La cosa migliore da tenere a mente è tenere traccia dei riferimenti ai tuoi oggetti. È molto facile finire con riferimenti sospesi ad oggetti che non ti interessano più. Se non hai più intenzione di utilizzare qualcosa, eliminalo.

Abituati a utilizzare un provider di cache con scadenze scorrevoli, in modo che se qualcosa non viene referenziato per l'intervallo di tempo desiderato, viene negato e ripulito. Ma se si accede molto, lo dirà in memoria.

Uno dei migliori strumenti sta usando Strumenti di debug per Windows e eseguendo un dump della memoria del processo utilizzando adplus , quindi utilizza windbg e il plug-in sos per analizzare la memoria di processo, i thread e le pile di chiamate.

È possibile utilizzare questo metodo anche per identificare i problemi sui server, dopo aver installato gli strumenti, condividere la directory, quindi connettersi alla condivisione dal server utilizzando (net use) e prendere un arresto anomalo o interrompere il dump del processo.

Quindi analizza offline.

Dopo una delle mie correzioni per l'applicazione gestita ho avuto la stessa cosa, ad esempio come verificare che la mia applicazione non abbia la stessa perdita di memoria dopo la mia prossima modifica, quindi ho scritto qualcosa come Framework di verifica rilascio oggetto, per favore prendi uno sguardo al pacchetto NuGet ObjectReleaseVerification . Puoi trovare un esempio qui https://github.com/outcoldman/OutcoldSolutions-ObjectReleaseVerification-Sample e informazioni su questo esempio http://outcoldman.ru/en/blog/show/322

Preferisco dotmemory da Jetbrains

Da Visual Studio 2015 prendere in considerazione l'utilizzo immediato Strumento diagnostico di utilizzo della memoria per raccogliere e analizzare i dati di utilizzo della memoria.

Lo strumento di utilizzo della memoria consente di eseguire una o più istantanee dell'heap di memoria nativa e gestita per comprendere l'impatto sull'utilizzo della memoria dei tipi di oggetti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top