2011-07-08 10 views
7

Ho bisogno di caricare dinamicamente molte (a volte centinaia) di immagini in miniatura. Per motivi di prestazioni ho bisogno di farlo in un numero limitato di richieste, sto usando una singola richiesta/risposta per il test. Sto inviando i dati binari per le immagini nella risposta e caricandole in BitmapImage utilizzando un MemoryStream. Funziona correttamente finché non carico più di 80 anteprime, quindi ottengo l'eccezione Catastrophic Failure. Per assicurarmi che i miei dati non fossero corretti, ho provato a caricare un BitmapImage più volte con lo stesso array di byte e si blocca dopo circa 80 carichi.Silverlight: BitmapImage dal flusso genera eccezioni (errore irreversibile (Eccezione da HRESULT: 0x8000FFFF (E_UNEXPECTED)))

Ecco un esempio di come l'immagine viene caricata dalla matrice di byte, l'array di byte è noto per avere dati di immagine validi (png):

private BitmapImage LoadImage(byte[] imageData) 
{ 
    BitmapImage img = new BitmapImage(); 
    MemoryStream stream = new MemoryStream(imageData); 
    img.SetSource(stream); // Exception thrown here after too many images loaded. 
    return img; 
} 

Ho quindi utilizzare il BitmapImage come fonte per un Elemento immagine sulla pagina, ma l'errore si verifica nella riga img.SetSource(...) in alto.

L'aggiunta di GC.Collect() al ciclo in cui sto caricando le immagini di anteprima mi consente di caricare qualche altra immagine, quindi penso che questo abbia a che fare con la gestione della memoria ma non so cosa posso fare per risolvere il problema .

+0

Non sono sicuro se questo potrebbe essere il problema ma MemoryStream ha proprietà ReadTimeout e WriteTimeout. Il flusso potrebbe scadere? – Danexxtone

+0

Ho provato a impostare ReadTimeout e ottenuto un'eccezione: i timeout non sono supportati su questo stream. – toby

+0

Puoi chiarire alcune cose: perché un array di byte? Non c'è uno stream dal download che potresti alimentare direttamente a "img.SetSource"?Sei sicuro che i file scaricati siano di dimensioni "miniatura" o stai scaricando immagini più grandi che vengono ridimensionate dal controllo immagine? Sono queste miniature di foto? – AnthonyWJones

risposta

6

Penso che citando la risposta che fornisce da Microsoft nel bug report sopra è utile dal momento che è molto succinta e descrittivo del problema, oltre a fornire una soluzione consigliata:

Quando Silverlight carica un'immagine, il framework mantiene un riferimento e mette in cache l'immagine decodificata finché il controllo di flusso non viene restituito al dispatcher del thread dell'interfaccia utente. Quando si caricano le immagini in un circuito chiuso come quello, anche se l'applicazione non conserva un riferimento, il GC non può liberare l'immagine finché non rilasciamo il nostro riferimento quando viene restituito il controllo di flusso.

Dopo aver elaborato circa 20 immagini, è possibile interrompere e mettere in coda il set successivo utilizzando Dispatcher.BeginInvoke solo per suddividere il lavoro elaborato in un unico batch. Questo ci consentirà di liberare immagini che non sono conservate dalla tua applicazione.

Capisco con il comportamento di decodifica attuale non è ovvio che Silverlight trattiene questi riferimenti, ma la modifica del design del decodificatore potrebbe influire su altre aree, quindi per ora consiglio di elaborare immagini come questa in lotti.

Ora, se si sta effettivamente tentando di caricare 500 immagini e conservarle, è comunque probabile che si esaurisca la memoria a seconda delle dimensioni dell'immagine. Se hai a che fare con un documento di più pagine, potresti invece caricare le pagine su richiesta in background e rilasciarle quando non sono visualizzate con poche pagine di buffer, in modo che in nessun punto superi i limiti di memoria delle texture ragionevoli.

Problemi correlati