2015-01-04 14 views
5

Gdybym wykonać kod poniżej OutOfMemoryException występuje na obu liniiC# bitmapy - nie mogę znaleźć jak usunąć OutOfMemoryException

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

lub linii

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

gdy wewnętrzna na rachunku stracony około 1000 razy.

Jednak nie wiem, dlaczego występuje wyjątek OutOfMemoryException. Myślę, że napisałem wystarczającą liczbę using, aby pozbyć się obiektów Bitmap. Gdzie występuje wyciek pamięci?

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. Być może dzieje się tak dlatego, że Parallel.ForEach spawnuje zadania przed zakończeniem innych zadań, więc więcej zadań jest uruchamianych, ale Bitmap s nie były GCed, ponieważ zadania nie zostały zakończone. Cóż, jeśli tak jest, jak to naprawić, aby uniknąć OutofMemoryException? Nie jestem pewien, czy tak jest jeszcze ...

+0

Być może MemoryFailPoint może pomóc (http://msdn.microsoft.com/en-us/library/system.runtime.memoryfailpoint%28v=vs.110%29.aspx) –

+1

Dokładny ten sam problem co [to pytanie] (http://stackoverflow.com/questions/25907829/why-is-parallel-foreach-much-szybciej- potem-równolegle-do-używania-nie-miesionych-). –

Odpowiedz

6

Wpadłem na podobne (ale nie na tyle podobne, aby chcieć oznaczyć to jako duplikat) issue myself. Możesz ustawić, aby ParallelOptions.MaximumDegreeOfParallelism nie tworzył dodatkowych zadań, jeśli zauważy, że utknął on w miejscu pracy.

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

Powodem otrzymujesz ten problem jest rzeczą, którą są związani nie CPU ale IO napędu podczas odczytu pliku wrócił z FrameToFilePath. Powoduje to niski CPU%, a Parallel.ForEach wykrywa niski% i stara się odrodzić więcej zadań, aby zwiększyć użycie do 100%. Ustawienie maksymalnej równoległości powoduje, że przestaje ona próbować osiągnąć 100% po utworzeniu określonej liczby zadań. Możesz użyć numeru większego niż Environment.ProcessorCount, ale głównym wąskim gardłem jest plik IO.