Domanda

ho pensato se c'è un modo per accelerare la liberazione della memoria in .NET. Sto creando un gioco in .NET (solo il codice gestito) in cui non è necessario alcun grafici significativi, ma ancora vorrei scriverlo correttamente al fine di non perdere le prestazioni per niente.

Per esempio è utile valore nullo assegnare ad oggetti che non sono necessari più? Vedo questo in alcuni campioni su Internet.

È stato utile?

Soluzione

  

è utile valore nullo assegnare agli oggetti che non sono necessari più?

In generale, no. La maggior parte dei campioni vedrete on-line che fanno questo sono da persone che è venuto a .Net da VB6, dove questa è stata una migliore pratica comune. In .Net, è meno utile. Se si dispone di un metodo molto lungo in esecuzione, potrebbe lasciare che il garbage collector trovare l'oggetto un po 'prima - ma se il vostro metodo è che a lungo si hanno altri problemi.

Al contrario, in .Net si dovrebbe costruire metodi brevi e definire le variabili più tardi possibile nei più piccoli blocchi ampia possibile. Utilizzare il corso della vita "naturale" della variabile come determinato dal campo di applicazione, ma mantenere quel breve vita naturale.

Si dovrebbe non essere facendo la propria raccolta dei rifiuti, come suggerito da almeno un altra risposta qui. Questo può effettivamente rendere le cose più lento . Net utilizza un garbage collector generazionale. Forzando una garbage collection, è potrebbe raccogliere l'oggetto di destinazione (anche voi non potrebbe - non ci sono garanzie con la raccolta dei rifiuti). Ma è probabile che anche forzare un sacco di altri oggetti che è possibile non raccoglie ancora essere memorizzati in una generazione di ordine superiore, che li rende più difficili da raccogliere in futuro. Quindi, solo non farlo.

Altri suggerimenti

Non si deve preoccupare troppo e non ottimizzare prematuramente. La gestione della memoria in .NET è automatico e molto efficiente. Se si inizia a 'ottimizzare' è necessario sapere esattamente cosa si sta facendo o si potrebbe rallentarlo.

Vai alla prima partita, e poi se è troppo lento utilizzare un profiler per trovare il problema. Molto probabilmente non sarà un problema di memoria.

La maggior parte della grafica oggetti connessi nella NET (immagine e la sua discendenza, grafica, penna, pennello, ecc) implementare IDisposable. Se avete intenzione di utilizzare un oggetto per un'operazione specifica, quindi non di nuovo, utilizzare il seguente schema:

using(var g = Graphics.FromBitmap(bmp))
{
    //Do some stuff with the graphics object
}

Facendo in questo modo garantirà eventuali risorse non gestite avranno liberato quando cadono fuori del campo di applicazione.

Trovo allocare oggetti in uno .net delle cose che influisce sulle prestazioni di più. Per ovviare a questo uso l'uno schema di fabbrica dove riciclo oggetti che ho usato. Qui è semplice implementazione generica:

internal class ListFactory<T> 
    where T: IRecyclable, new()
{
    private List<T> _internalList;
    private int _pointer;

    public ListFactory()
    {
        _internalList = new List<T>();
        _pointer = 0;
    }

    public void Clear()
    {
            _pointer = 0;
    }

    public int Count
    {
        get
        {
            return _pointer;
        }
    }

    public List<T> InnerList
    {
        get
        {
            return _internalList;
        }
    }

    //Either return T form the list or add a new one
    //Clear T when it is being reused
    public T Create()
    {
        T t;

        //If the pointer is less than the object count then return a recycled object
        //Else return a new object 
        if (_pointer < _internalList.Count )
        {
            t = _internalList[_pointer];
            t.Recycle();
        }
        else
        {
            t = new T();
            _internalList.Add(t);
        }
        _pointer ++;
        return t;
    }
}

Per la mia linea di algoritmo di routing, ho bisogno di tenere costantemente molti valori come RouteNode , che implementa la seguente interfaccia:

public interface IRecyclable
{
    void Recycle();
}

Si ottiene costantemente creato e distrutto. Per riciclare questi oggetti, creare un nuovo stabilimento:

nodeFactory = new ListFactory<RouteNode>();

Quando avete bisogno di un oggetto, chiamare il metodo Create:

RouteNode start = nodeFactory.Create();
RouteNode goal = nodeFactory.Create();

Quando avete finito con gli oggetti nella lista, cancellare l'elenco. Il puntatore viene reimpostato l'inizio della lista, ma gli oggetti stessi non vengono distrutti. Infatti il ??metodo Riciclo viene chiamato solo quando l'oggetto viene recuperato nuovamente. (Si consiglia di fare questo prima se si dispone di altri riferimenti a oggetti, vedere i commenti qui sotto)

Questa è un'implementazione abbastanza ingenuo, ma è un punto di partenza.

Può essere utile in alcuni casi ad oggetti impostato su NULL che non sono più necessari. Spesso è inutile o controproducente, ma non sempre. Quattro principali situazioni in cui può essere utile:

campi
  • oggetti contenenti dichiarati come "WithEvents" in vb.net dovrebbero implementare IDisposable, e dovrebbero annullato quei campi nel metodo Dispose. Non so il motivo per cui vb.net non include un bel modo di nulling automaticamente i campi WithEvents, ma dal momento che non è così che deve essere cancellata manualmente.
  • Se una variabile locale contiene un riferimento a un oggetto che di fatto non potrà mai essere usato di nuovo, ma può essere un po 'prima che il codice raggiunge un punto in cui il compilatore conosce la variabile non andranno utilizzati, la compensazione la variabile può consentire il riferimento di essere liberato prima.
  • Se a un certo punto una matrice che è grande o è già da qualche tempo è noto per essere inutile, e se i riferimenti a alcuni oggetti recente allocati sono memorizzati in esso, liberando tali riferimenti prima distruggere ogni superstite riferimenti alla matrice possono consentire gli oggetti appena creati per essere liberati molto prima di quello che altrimenti sarebbe.
  • Se un oggetto ha una routine Finalize ed è nella coda di finalizzazione, tutti gli oggetti direttamente o indirettamente, a cui fa riferimento lo saranno esentati dal garbage collection. Di conseguenza, gli oggetti finalizable non devono fare riferimento a tutto ciò che non sarà necessario per la finalizzazione.

        
  • Per fare questo (e ho avuto a che fare questo con frequenti> allocazioni 50MB), chiamata:

            myObj = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
    

    Ho notato che l'occupazione di memoria delle app sarà poi notevolmente diminuire. In teoria, non dovrebbe essere necessario fare questo. Tuttavia, in pratica, con un Windows 32 bit OS si potrebbe ottenere 2 blocchi contigui di> 300 MB liberi in un dato momento, e avere lo spazio occupato da un sacco di piccoli allocazioni o una serie di quelli più grandi può significare che altre grandi allocazioni sarà riuscire inutilmente. Le piste garbage collector in background quando si può, ma se si deve assolutamente fare grandi allocazioni in questo momento, che insieme di linee che contribuisce a rendere possibile per me.

    EDIT:. Da quello che ho messo nei commenti, per le downvoters

    Se andate a leggere l'intero post sulla raccolta dei rifiuti da Rico Mariani , si noterà che le grandi, poco frequenti, allocazioni di memoria non prevedibili rientrano in scenario # 2. A Pentecoste:

      

    Regola # 2

         

    Si consideri chiamando GC.Collect () se qualche   non ricorrenti evento è appena accaduto   e questo evento è altamente probabile che   hanno causato un sacco di vecchi oggetti   die.

         

    Un esempio classico di questo è se si è   scrittura di un'applicazione client e si   visualizzare una molto grande e complicato   forma che ha un sacco di dati associati   con esso. Il tuo utente deve solo   interagito con questa forma potenzialmente   la creazione di alcuni oggetti di grandi dimensioni ... cose   come documenti XML, o un grande DataSet   o due. Alla chiusura della maschera questi   oggetti sono morti e così GC.Collect ()   sarà recuperare la memoria associata   con loro.

         

    Ora perché dovrei suggerire questo come un   tempo possibile chiamare il collettore?   Voglio dire, il mio solito consiglio vale qualcosa   come "il collettore è auto-tuning in modo   Non si scherza con esso ". Perché il cambiamento   di atteggiamento si potrebbe chiedere?

         

    Beh qui è una situazione in cui il   tendenza da collezione [sic] per cercare di prevedere   il futuro sulla base del passato, è probabile   a non avere successo.

    Se si effettua grandi allocazioni nel vostro gioco, sarà necessario essere attenti a come la memoria viene gestito. Le opere garbage collector di previsione basate su eventi passati, e grandi blocchi di memoria su una macchina a 32 bit può essere devastante per future assegnazioni, se non adeguatamente gestito. Se non lo avete fatto, non scontato che mi sbaglio; se avete fatto, mi rallegro una spiegazione di come farlo correttamente (vale a dire, come la memoria defrag per assicurarsi che posso sempre allocazione 50-100MB della memoria in un dato momento).

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