2011-10-15 15 views
5

Scrivo un codice che legge un'immagine png dal file e mostra con controllo.
voglio leggere l'immagine dal flusso e impostareeccezione di memoria esaurita quando si utilizza control.BackgroundImage = Image.FromStream (memStream);

control.BackgroundImage = Image.FromStream(memStream); 

ma quando l'uso di questo codice, si verificano "out of memory" eccezione. ma quando utilizzare

control.Image = Image.FromStream(memStream); 

o

control.BackgroundImage = Image.FromFile(fileSource); 

, che è il lavoro.

la dimensione del file immagine è 5 KB.

if (System.IO.File.Exists(imgSource)) 
{ 
    using (FileStream localFileStream = new FileStream(imgSource, FileMode.Open)) 
    { 
    using (MemoryStream memStream = new MemoryStream()) 
    { 
    int bytesRead; 
    byte[] buffer = new byte[1024]; 

    while ((bytesRead = localFileStream.Read(buffer, 0, buffer.Length)) > 0) 
    { 
     memStream.Write(buffer, 0, bytesRead); 
    } 
    retIMG = Image.FromStream(memStream); 

    pictureBox1.Image = retIMG;  // is work 
    label1.Image = retIMG;  // is work 
    button1.Image = retIMG;  // is work 
    button1.BackgroundImage = retIMG; // don't work 
    groupBox1.BackgroundImage = retIMG; // don't work 
    panel1.BackgroundImage = retIMG; // don't work 
    } 
    } 
} 

Penso che un bug nel framework .NET. per favore mi aiuti?

+0

Quale è il problema? Ti suggerisco di mettere prima l'immagine in una variabile, poi assegnarla alla seconda operazione. Quanto è grande l'immagine? La dimensione del file 5ggb può essere 50.000x50.000 pixel;) – TomTom

+1

Le immagini riportano "Memoria insufficiente" per tutto ciò che va storto. –

+0

Proprio come ha detto Henk, GDI + (e quindi 'System.Drawing') genera errori OutOfMemory in molti casi in cui non è effettivamente esaurito la memoria, come parametri non validi. Immagino che questo sia uno di quelli. – CodesInChaos

risposta

6

Dare un po 'di background da aggiungere alla risposta corretta di DeCaf. GDI + si sforza molto per evitare di copiare i pixel di una bitmap. Questo è costoso, i bitmap che richiedono dozzine di megabyte non sono inusuali. Quando si carica una bitmap da un file con il costruttore Bitmap o Image.FromFile(), GDI + crea un file mappato in memoria. I pixel vengono cercati su richiesta, solo quando necessario. Molto efficiente ma mette un blocco sul file. Chiaramente stavi cercando di evitarlo in questo codice.

Si evita effettivamente tale blocco caricando i byte in memoria con un MemoryStream. Ma lo stesso principio si applica ancora, GDI + continua a non copiare i pixel e legge solo dallo streaming quando è necessario. Questo va storto quando Dispose() lo stream. Molto difficile da diagnosticare perché l'eccezione si verifica in seguito, in genere quando è necessario disegnare la bitmap. Bombarda nel codice della pittura, non hai alcun codice da guardare ma Application.Run(). Con un messaggio di eccezione scadente, GDI + ha solo una manciata di codici di errore. Sei non memoria insufficiente, sembra solo in questo modo per GDI +, non può altrimenti capire perché il flusso improvvisamente non è più leggibile.

Almeno una parte del problema è dovuta all'implementazione molto scomoda di MemoryStream.Dispose(). Dispose ha lo scopo di liberare le risorse non gestite. Un flusso di memoria non ne ha, possiede solo memoria.Questo è già stato curato dal garbage collector. Purtroppo lo hanno comunque implementato. Non eliminando nulla, dal momento che non c'è niente da smaltire, ma contrassegnando il MemoryStream illeggibile. Che attiva l'errore in GDI + quando tenta di leggere mentre disegna la bitmap.

Quindi è sufficiente rimuovere utilizzando la dichiarazione per evitare di smaltire MemoryStream per risolvere il problema. E non preoccuparti di smaltirlo più tardi quando la bitmap non è più in uso. Non c'è niente da smaltire, il garbage collector libera automaticamente la memoria.

+0

In realtà il 'MemoryStream' può contenere risorse non gestite sotto forma di un' WaitHandle', ovvero se è stato richiamato 'BeginRead' o' BeginWrite' su di esso. È improbabile che ci sia un problema qui, ma ho pensato di segnalarlo comunque. – DeCaf

+0

Vero. Effettivamente improbabile. –

+1

+1 per una spiegazione molto bella dello sfondo! – DeCaf

7

Leggi i commenti su Image.FromStream su MSDN:

è necessario mantenere il flusso aperto per tutta la durata del Immagine.

Quindi, se si rimuove il using intorno alla creazione del vostro MemoryStream il codice funziona bene.

Ovviamente si deve preferibilmente smaltire il MemoryStream una volta che non è più necessario il Image si è creato, anche se è probabile nulla di male in questo caso non chiamare Dispose() e lasciando al GC per raccogliere una volta inutilizzato.

Il fatto che sembra funzionare con parte del codice è probabilmente pura fortuna e non deve essere considerato una soluzione funzionante. Leggi sempre la documentazione per scoprire le stranezze come questa.

Problemi correlati