2015-01-04 13 views
5

Se eseguo il codice qui sotto, OutOfMemoryException avviene sia presso la linea diC# Bitmap - Non riesco a trovare come rimuovere OutOfMemoryException

using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1))) 

o la linea

using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1))) 

Quando viene eseguito il interno per dichiarazione circa 1000 volte.

Tuttavia, non so perché si verifichi OutOfMemoryException. Penso di aver scritto abbastanza using per disporre gli oggetti Bitmap. Dove si verifica la perdita di memoria?

class Program 
{ 
    static void Main(string[] args) 
    { 
     // Some code to initialize List<Interval> intervals 

     Parallel.ForEach(intervals, interval => 
     { 
      using (Bitmap bitmap1 = new Bitmap(FrameToFilePath(interval.Start - 1))) 
      using (Bitmap bitmap2 = new Bitmap(FrameToFilePath(interval.End + 1))) 
      { 
       for (int i = interval.Start; i <= interval.End; i++) 
       { 
        ColorMatrix colorMatrix = new ColorMatrix(); // Identity matrix 
        colorMatrix.Matrix33 = (i - interval.Start + 1F)/(interval.Span + 1F); // Alpha 

        using (ImageAttributes imageAttributes = new ImageAttributes()) 
        using (Bitmap intermediate = new Bitmap(bitmap1.Width, bitmap1.Height, PixelFormat.Format32bppArgb)) 
        using (Graphics graphics = Graphics.FromImage(intermediate)) 
        { 
         imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 

         graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver; 

         graphics.DrawImage(bitmap1, 0, 0); 
         graphics.DrawImage(bitmap2, new Rectangle(0, 0, intermediate.Width, intermediate.Height), 0, 0, bitmap2.Width, bitmap2.Height, GraphicsUnit.Pixel, imageAttributes); 

         intermediate.Save(FrameToFilePath(i), ImageFormat.Png); 
        } 
       } 
      } 
     }); 
    } 

    static string FrameToFilePath(int frame) 
    { 
     return string.Format(@"C:\(some path)\frames\frame-{0:00000}.png", frame); 
    } 
} 

class Interval 
{ 
    public int Start { get; set; } 
    public int End { get; set; } 
    public int Span { get { return End - Start + 1; } } 
} 

EDIT: OK. Forse perché Parallel.ForEach spawnà le attività prima che le altre attività siano terminate, in modo che vengano avviate sempre più attività, ma i numeri Bitmap non erano GC in quanto le attività non erano state terminate. Bene, se questo è il caso, come risolverlo per evitare OutofMemoryException? Non sono sicuro che sia ancora così ...

+0

Forse un MemoryFailPoint può essere di aiuto (http://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint%28v=vs.110%29.aspx) –

+1

Esattamente lo stesso problema di [questa domanda] (http://stackoverflow.com/questions/25907829/why-is-parallel-foreach-much-faster-then-asparallel-forall-even-though-msdn). –

risposta

6

Mi sono imbattuto in un simile (ma non abbastanza simile per me da voler contrassegnare questo come duplicato) issue myself. Quello che puoi fare è impostare ParallelOptions.MaximumDegreeOfParallelism per non creare attività extra se vede che il lavoro è in stallo.

Parallel.ForEach(intervals, 
    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
    (interval) => 
     { 
      //... 
     }); 

La ragione si stanno ottenendo questo problema è la cosa si sono tenuti, non è la CPU, ma l'IO del drive durante la lettura del file restituito da FrameToFilePath. Ciò causa una bassa percentuale di CPU e Parallel.ForEach rileva quella percentuale bassa e tenta di generare più attività per portare l'utilizzo fino al 100%. Impostando il parallelismo massimo si dice di smettere di cercare di raggiungere il 100% una volta che è stato creato un determinato numero di attività. È possibile utilizzare un numero maggiore di Environment.ProcessorCount ma il collo di bottiglia principale è il file IO.

Problemi correlati