2017-02-13 2 views
0

Ich arbeite an einer Software in C# zum Bearbeiten von Bildern. Ich habe viele Bilder (mehr als 11.000), und wenn ich mein Programm nach wenigen Minuten ausführen, ich habe eine „OutOfMemoryException“Array in Schleife erstellen Raise eine OutOfMemoryException

Es ist mein Code:

private void GenerateImages() 
{ 
    try 
    { 
     Parallel.ForEach(listImagesStart, startImg => 
     { 
      bool docontinue = true; 
      try 
      { 
       startImg.LoadImage(_baseFileResults); 
      } 
      catch 
      { 
       docontinue = false; 
      } 
      if (docontinue) 
      { 
       //Save image as file 
       startImg.Save(); 

       // Do rotate 
       MyImg lastRotate = baseImg; 
       MyImg imgtmp; 
       String[] tabRotate = new String[3] { "_90", "_180", "_270"}; 
       foreach (String rotate in tabRotate) 
       { 
        imgtmp = new GenImg(baseImg.FileName + rotate + baseImg.FileExtension); 
        imgtmp.LoadImage(lastRotate); 
        imgtmp.Rotate90(); 
        imgtmp.Save(); 
        lastRotate = imgtmp; 
       } 

       startImg.Dispose(); 
       imgtmp.Dispose(); 
      } 
     }); 
    } 
    catch (Exception e) 
    { 
     MessageBox.Show(e.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); 
#if DEBUG 
     MessageBox.Show(e.StackTrace, "Error", MessageBoxButton.OK, MessageBoxImage.Error); 
#endif 
    } 
} 

Und MyImg:

class myImg 
{ 
    public Byte[] Matrix; 
    public int Height; 
    public int Width; 

    public void LoadImage(String filePath) 
    { 
     // create new Matrix/Heigth/Width from file 
    } 

    public void LoadImage(myImg img) 
    { 
     Matrix = new Byte[img.Matrix.Length]; 
     Array.Copy(img.Matrix, Matrix, img.Matrix.Length); 
     Height = img.Height; 
     Width = img.Width; 
    } 

    public void Rotate90() 
    { 
     // Save before 
     int tmpWidth = Height; 
     int tmpHeight = Width; 
     Byte[] tmpMatrix = new Byte[Matrix.Length]; 

     for (int r = 0; r < tmpHeight; r++) 
     { 
      for (int c = 0; c < tmpWidth; c++) 
      { 
       int prevR = Height - c - 1; 
       int prevC = r; 
       tmpMatrix[c + r * tmpWidth] = Matrix[prevC + prevR * Width]; 
      } 
     } 

     // Copy new image 
     Array.Copy(tmpMatrix, Matrix, Matrix.Length); 
     Width = tmpWidth; 
     Height = tmpHeight; 
    } 

    public void Dispose() 
    { 
     SavePath = null; 
     Matrix = null; 
     Points = null; 
     Width = 0; 
     Height = 0; 
     GC.Collect(); 
    } 
} 

Die SystemOutOfMemoryException tritt bei Anweisung new Byte[Length] auf. Ich denke, ich erstelle zu viele Arrays, aber ich weiß nicht, was ich tun soll.

+0

In Ihrem foreach-Schleife rufen Sie imgtmp.LoadImage sowie rotate90 beide alllocate den Speicher. Ist das die Schleife, wo Sie 11000 Bilder verarbeiten? Darüber hinaus erwähnen Sie nicht, wie groß jedes Bild ist. Sie rufen nicht auf, bis Sie diese Schleife verlassen. Und diese foreach-Schleife ist innerhalb einer Parallele für. Sie sollten überdenken, wie Sie Ihren Dispose aufrufen. –

+0

@DaveS Ich bearbeite meine 11000 Bilder in 'Parallel.Foreach', die Liste ist' listImagesStart'. Bilder sind 700x700 Pixel. Ich habe meinen Code so geändert, dass er "Dispose" aufruft, wenn "docover" falsch ist. (Ich warte auf Ergebnisse) –

Antwort

1

Das Hauptproblem ist, dass listImagesStart Verweis von jedem startImg Artikel behält. Dies verhindert, dass GC Speicher freigibt, der von myImg.LoadImage zugewiesen wurde (mit dem Array Matrix).

Eine schnelle Lösung: Sie können Matrix auf Null setzen, um den Speicher zu recyceln.

public void UnLoadImage() 
{ 
     Matrix = null ; // this will allow GC to recycle memory used by Matrix 
} 

dann (Ich entfernte die nutzlos docontinue Variable):

try 
{ 
    startImg.LoadImage(_baseFileResults); 

    //Save image as file 
    startImg.Save(); 

    // Do rotate 
    MyImg lastRotate = baseImg; 
    MyImg imgtmp; 
    String[] tabRotate = new String[3] { "_90", "_180", "_270"}; 
    foreach (String rotate in tabRotate) 
    { 
     imgtmp = new GenImg(baseImg.FileName + rotate + baseImg.FileExtension); 
     imgtmp.LoadImage(lastRotate); 
     imgtmp.Rotate90(); 
     imgtmp.Save(); 
     lastRotate = imgtmp; 
    } 

    startImg.Dispose(); 
    imgtmp.Dispose(); 
} 
catch 
{ 

} 
finally 
{ 
     startImg.Unload(); // Here is the trick 
} 
+0

Kann ich mein 'Dispose' anstatt' UnLoadImage' aufrufen? Meine Dispose machen die 'Matrix = null' –

+0

Sie sind frei, UnloadImage zu Dispose() umzubenennen und implementiert IDisposable – Ksv3n

+0

Bitte Kommentar warum Sie downvoted? – Ksv3n