Domanda

Ho un problema in cui un paio di 3 matrici tridimensionali assegnano una grande quantità di memoria e il programma a volte ha bisogno di sostituirli con quelli più grandi / piccoli e lancia un OutOfMemoryException.

Esempio: ci sono 5 matrici allocate 96Mb (200x200x200, 12 byte di dati in ogni ingresso) e il programma deve sostituirli con 210x210x210 (111MB). E lo fa in un modo simile a questo:

array1 = new Vector3[210,210,210];

Dove array1-array5 sono gli stessi campi utilizzati in precedenza. Questo dovrebbe impostare le vecchie matrici come candidati per la raccolta dei rifiuti, ma apparentemente il GC non agire abbastanza in fretta e lascia le vecchie matrici ripartite prima ripartizione delle nuove - che causa l'OOM - mentre se essi dove liberati prima che le nuove assegnazioni lo spazio dovrebbe essere sufficiente.

Quello che sto cercando è un modo per fare qualcosa di simile:

GC.Collect(array1) // this would set the reference to null and free the memory
array1 = new Vector3[210,210,210];

Non sono sicuro se uno spazzatura collecion completa sarebbe una buona idea, dato che il codice può (in alcuni casi) devono essere eseguito abbastanza spesso.

C'è un modo corretto di fare questo?

È stato utile?

Soluzione

Questa non è una risposta esatta alla domanda iniziale, "come forzare GC', eppure, penso che vi aiuterà a riesaminare il problema.

Dopo aver visto il tuo commento,

  • Mettere il GC.Collect (); sembra aiutare, lavori finanziari ancora non risolve completamente il problema - per qualche motivo il programma si blocca ancora quando circa 1,3 GB sono allocati (sto usando System.GC.GetTotalMemory (false); per trovare la quantità reale assegnato).

Vi sospetta che si può avere la frammentazione di memoria . Se l'oggetto è di grandi dimensioni (85000 bytes sotto .net 2.0 CLR se non ricordo male, non so se è stato cambiato o no), l'oggetto verrà assegnato in un mucchio speciale, Grande Heap Object (LOH) . GC fa recuperare la memoria utilizzata dagli oggetti irraggiungibili in LOH, ancora, che non esegue compattazione, in LOH come fa agli altri cumuli (gen0, gen1 e gen2), a causa delle prestazioni.

Se non frequente allocare e rilasciare oggetti di grandi dimensioni, si farà LOH frammentato e anche se si dispone di più memoria libera in totale di che cosa avete bisogno, non si può avere uno spazio di memoria contigua più, quindi, otterrà un'eccezione OutOfMemory.

Mi vengono in mente due soluzioni in questo momento.

  1. Sposta in 64-bit macchina / OS e approfittarne :) (più semplice, ma forse più dura così a seconda delle vostre vincoli di risorse)
  2. Se non si può fare # 1, quindi provare a destinare un enorme mandrino di memoria prima e di utilizzarli (si può richiedere di scrivere qualche classe helper per manipolare una matrice più piccola, che di fatto risiede in un array più grande) per evitare la frammentazione . Questo può aiutare un po ', tuttavia, potrebbe non risolvere completamente il problema e si può avere a che fare con la complessità.

Altri suggerimenti

Sembra hai incontrato LOH (Large oggetto heap) problema di frammentazione.

Large Object Heap

CLR Inside Out Large Object Heap Scoperti

È possibile controllare per vedere se hai problemi di frammentazione Loh utilizzando SOS

Controlla questo domanda per un esempio di come utilizzare SOS per ispezionare il Loh.

Forzare una garbage collection non è sempre una buona idea (si può effettivamente promuovere i tempi di vita degli oggetti in alcune situazioni). Se si deve, si può usare:

array1 = null;
GC.Collect();
array1 = new Vector3[210,210,210];

Non è questo solo grande frammentazione oggetto mucchio? Oggetti> 85.000 byte sono allocati sulla grande mucchio oggetto. Il GC consente di liberare spazio in questo mucchio, ma mai compatta gli oggetti rimanenti. Ciò può portare a memoria contigua insufficent di allocare correttamente un oggetto di grandi dimensioni.

Alan.

Se dovessi speculare si problema in realtà non è che si sta andando da Vector3 [200.200.200] a un Vector3 [210.210.210] ma che molto probabilmente avete simili passaggi precedenti prima di questo:

 i.e.   
    // first you have
    Vector3[10,10,10];
    // then
    Vector3[20,20,20];
    // then maybe
    Vector3[30,30,30];
    //  .. and so on ..
    //  ...
    // then
    Vector3[200,200,200];
    // and eventually you try
    Vector3[210,210,210] // and you get an OutOfMemoryException..

Se questo è vero, vorrei suggerire una migliore strategia di allocazione. Prova over assegnazione - forse raddoppiando le dimensioni ogni volta che al contrario di allocazione sempre e solo lo spazio di cui avete bisogno. Specialmente se queste matrici sono mai utilizzati dagli oggetti che devono pin i tamponi (cioè se che hanno legami con codice nativo)

Così, invece di quanto sopra, avere qualcosa di simile:

 // first start with an arbitrary size
 Vector3[64,64,64];
 // then double that
 Vector3[128,128,128];
 // and then.. so in thee steps you go to where otherwise 
 // it would have taken you 20..
 Vector3[256,256,256];

Non potrebbe essere sempre raccolti perché sono in corso di riferimento da qualche parte che non ti aspetti.

Come prova, prova a cambiare i vostri riferimenti a WeakReferences , invece, e vedere se ciò risolve il problema OOM. Se non lo fa, allora li stai riferimento da qualche altra parte.

Capisco quello che stai cercando di fare e spingere per la raccolta dei rifiuti immediato non è probabilmente l'approccio giusto (dal momento che il GC è sottile nei suoi modi e veloce da rabbia).

Detto questo, se si voler che la funzionalità, perché non creare vero?

public static void Collect(ref object o)
{
    o = null;
    GC.Collect();
}

Un'eccezione OutOfMemory innesca internamente un ciclo di GC automaticamente una sola volta e tenta di nuovo l'assegnazione prima di poter realmente lanciare l'eccezione al codice. L'unico modo in cui si potrebbe essere avere eccezioni OutOfMemory è che se siete in possesso di riferimenti a troppa memoria. Cancellare i riferimenti più presto possibile assegnando loro nulla.

Una parte del problema potrebbe essere che si sta assegnando un array multidimensionale, che è rappresentato come un unico blocco contiguo di memoria sul mucchio oggetto di grandi dimensioni (maggiori informazioni qui ). Questo può bloccare altre destinazioni in quanto non v'è un blocco contiguo libero di utilizzare, anche se v'è ancora spazio libero da qualche parte, quindi l'OOM.

Prova ripartizione come una matrice irregolare - Vector3 [210] [210] [210] - che diffonde le matrici intorno memoria anziché come un unico blocco, e vedere se questo migliora materia

John, Creazione di oggetti> 85000 byte farà l'oggetto finiscono nel grande mucchio oggetto. Il grande mucchio oggetto viene mai compattato, invece lo spazio libero viene riutilizzato. Ciò significa che se si assegnano matrici più grandi ogni volta, si può finire in situazioni in cui LOH è frammentato, quindi l'OOM.

è possibile verificare questo è il caso rompendo con il debugger al punto di OOM e ottenere una discarica, presentando questa discarica a MS tramite un bug di connessione ( http://connect.microsoft.com ) sarebbe un ottimo inizio.

Quello che posso assicurare è che il GC farà la cosa giusta cercando di soddisfare voi richiesta di assegnazione, questo include dando il via un GC per pulire la vecchia spazzatura per soddisfare le nuove richieste di allocazione.

Non so che cosa è la politica di ripartizione dump di memoria su StackOverflow, ma sarei felice di dare uno sguardo per capire il vostro problema più.

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