Domanda

La mia applicazione framework compatta crea un elenco a scorrimento uniforme eseguendo il rendering di tutti gli elementi su una grande superficie bitmap, quindi copiando quella bitmap in una posizione di offset sullo schermo in modo da mostrare solo gli elementi appropriati. Le versioni precedenti rendevano solo gli elementi che avrebbero dovuto apparire sullo schermo in quel momento, ma questo approccio era troppo lento per un'interfaccia scorrevole scorrevole.

Di tanto in tanto genera una OutOfMemoryException durante la creazione iniziale della bitmap di grandi dimensioni. Se l'utente esegue un ripristino software del dispositivo ed esegue nuovamente l'applicazione, è in grado di eseguire la creazione senza problemi.

Non sembra che questa bitmap sia generata nella memoria del programma, poiché l'applicazione utilizza approssimativamente la stessa quantità di memoria del programma che aveva prima dei nuovi metodi di scorrimento uniforme.

Esiste un modo per impedire questa eccezione? Esiste un modo per liberare la memoria di cui ho bisogno (ovunque si trovi) prima che venga generata l'eccezione?

È stato utile?

Soluzione

Suggerirei di tornare al vecchio meccanismo di renderizzare solo una parte dei dati, dato che la dimensione dei dati con rendering completo è ovviamente un problema. Per aiutare a prevenire problemi di rendering probabilmente pre-renderizzerei alcune righe sopra e sotto la vista corrente in modo che possano essere "fatte scorrere". con un impatto limitato.

Altri suggerimenti

E appena ho pubblicato ho pensato a qualcosa che puoi fare per risolvere il tuo problema con la nuova versione. Il problema che hai è uno di CF che cerca di trovare un blocco di memoria contigua disponibile per l'enorme bitmap, e questo a volte è un problema.

Invece di creare una grande bitmap, puoi invece creare una raccolta di bitmap più piccole, una per ogni elemento, e renderizzare ogni elemento sulla sua piccola bitmap. Durante la visualizzazione, è sufficiente copiare le bitmap necessarie. CF avrà un tempo molto più semplice nel creare un mucchio di piccole bitmap rispetto a uno grande, e non dovresti avere problemi di memoria a meno che questo non sia un mucchio davvero enorme di elementi.

Dovrei evitare espressioni come " non esiste una soluzione " ;.

Un altro punto importante: assicurati di chiamare Dispose () su ogni bitmap quando hai finito con esso.

La tua bitmap sicuramente è in fase di creazione nella memoria del programma. La quantità di memoria necessaria per la bitmap dipende da quanto è grande e se questa dimensione richiesta genererà o meno OutOfMemoryException dipende dalla quantità disponibile per il PDA (che rende questo errore casuale).

Siamo spiacenti, ma in genere si tratta di una tecnica di rendering del controllo sconsigliabile (soprattutto su Compact Framework) per la quale non esiste alcuna soluzione all'aumentare della memoria fisica sul PDA, che di solito non è possibile (e spesso non risolve il problema comunque, poiché un processo CF è limitato a 32 MB, indipendentemente dalla disponibilità del dispositivo).

La soluzione migliore è tornare alla versione precedente e migliorare la sua velocità di rendering. C'è anche una semplice tecnica disponibile su CF per creare un controllo con doppio buffer per eliminare lo sfarfallio.

Dal momento che sembra che hai incontrato una limitazione del dispositivo che sta limitando la dimensione totale dello spazio Bitmap che puoi creare (questi sono apparentemente creati nella RAM video piuttosto che nella memoria generale del programma), un'alternativa è sostituire il grande oggetto Bitmap usato qui con un semplice blocco di memoria di Windows, accedendo per la lettura e la scrittura da PInvoking la funzione API BitBlt.

Inizialmente creare il blocco di memoria è complicato, e probabilmente vorrai porre un'altra domanda SO a riguardo (GCHandle.Alloc può essere usato qui per creare un oggetto " appuntato " ciò significa che .NET non è autorizzato a spostalo in memoria, che è fondamentale qui). So come farlo, ma non sono sicuro di farlo correttamente e preferirei avere il contributo di un esperto.

Dopo aver creato il blocco grande, devi scorrere i tuoi elementi, renderizzarli su una piccola bitmap che continui a riutilizzare (usando il tuo codice .NET esistente) e BitBlt nel punto appropriato nel tuo blocco di memoria.

Dopo aver creato l'intera cache, il tuo codice di rendering dovrebbe funzionare come prima, con la differenza che invece di copiare dalla grande bitmap alla tua superficie di rendering, BitBlt dal tuo blocco di cache. Gli argomenti per BitBlt sono essenzialmente gli stessi di DrawImage (destinazione, sorgente, coordinate e dimensioni, ecc.).

Dato che stai creando la cache dalla memoria normale in questo modo anziché dalla RAM video specializzata, non credo che incontrerai lo stesso problema. Tuttavia, farei sicuramente funzionare prima il codice di creazione del blocco e testerei per assicurarmi che possa creare un blocco abbastanza grande ogni volta.

Aggiornamento: in realtà, l'approccio ideale sarebbe quello di avere una raccolta di blocchi di memoria più piccoli piuttosto che uno grande (come pensavo fosse il problema con l'approccio Bitmap), ma hai già abbastanza da fare. Ho lavorato con le app CF che si occupano di oggetti da 5 e 10 MB e non è comunque un grosso problema (anche se potrebbe essere un problema più grande quando quel pezzo è bloccato - non lo so). A proposito, sono sempre stato sorpreso dagli OOME sulla creazione di BitMap perché sapevo che le bitmap erano molto più piccole della memoria disponibile, come te - ora so perché. Mi dispiace, all'inizio ho pensato che fosse una soluzione facile.

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