OutOfMemoryException, wenn Sie mehrere byte-arrays

Ich bin ständig schlagen einen OutOfMemoryException innerhalb einer Methode erzeugt und verarbeitet einige byte-arrays. Der code sieht so aus:

  1. Erzeugen MemoryStream, um einige Daten (über 60MB).
  2. Erstellen byte-array (gleiche Größe wie MemoryStream, über 60MB)
  3. Füllen Sie das array mit den bytes aus dem Speicher-stream
  4. Schließen MemoryStream
  5. Prozess Daten aus dem byte-array
  6. Lassen Methode

Wenn diese Methode aufgerufen wird, wie die 20-30 mal, die ich bekommen OutOfMemoryException Recht, wo das byte-array zugeordnet ist. Aber ich glaube nicht, dass es die system-Speicher-Problem. Anwendung Speichernutzung ist rund 500MB (private working set) und dem test-Maschine ist 64-bit mit 4GB RAM.

Ist es möglich, dass der Speicher verwendet werden, indem das byte-array oder MemoryStream wird nicht freigegeben, nachdem die Methode beendet wird? Aber dann, es sieht nicht aus wie dieser Speicher reserviert für den Prozess als private working set ist nur 500MB oder so.

Was kann die Ursache des OutOfMemoryException wenn große byte-array (60MB) neben physikalischen Speicher Mangel?

[Bearbeitet, um hinzufügen code-Beispiel]
Quelle stammt aus PdfSharp lib

Ausnahme wird ausgelöst bei Zeile byte[] imageBits = new byte[streamLength]; Es in der Tat aussieht wie LOH Fragmentierung Problem.

///<summary>
///Reads images that are returned from GDI+ without color palette.
///</summary>
///<param name="components">4 (32bpp RGB), 3 (24bpp RGB, 32bpp ARGB)</param>
///<param name="bits">8</param>
///<param name="hasAlpha">true (ARGB), false (RGB)</param>
private void ReadTrueColorMemoryBitmap(int components, int bits, bool hasAlpha)
{
  int pdfVersion = Owner.Version;
  MemoryStream memory = new MemoryStream();
  image.gdiImage.Save(memory, ImageFormat.Bmp);
  int streamLength = (int)memory.Length;

  if (streamLength > 0)
  {
    byte[] imageBits = new byte[streamLength];
    memory.Seek(0, SeekOrigin.Begin);
    memory.Read(imageBits, 0, streamLength);
    memory.Close();

    int height = image.PixelHeight;
    int width = image.PixelWidth;

    if (ReadWord(imageBits, 0) != 0x4d42 || //"BM"
        ReadDWord(imageBits, 2) != streamLength ||
        ReadDWord(imageBits, 14) != 40 || //sizeof BITMAPINFOHEADER
        ReadDWord(imageBits, 18) != width ||
        ReadDWord(imageBits, 22) != height)
    {
      throw new NotImplementedException("ReadTrueColorMemoryBitmap: unsupported format");
    }
    if (ReadWord(imageBits, 26) != 1 ||
      (!hasAlpha && ReadWord(imageBits, 28) != components * bits ||
       hasAlpha && ReadWord(imageBits, 28) != (components + 1) * bits) ||
      ReadDWord(imageBits, 30) != 0)
    {
      throw new NotImplementedException("ReadTrueColorMemoryBitmap: unsupported format #2");
    }

    int nFileOffset = ReadDWord(imageBits, 10);
    int logicalComponents = components;
    if (components == 4)
      logicalComponents = 3;

    byte[] imageData = new byte[components * width * height];

    bool hasMask = false;
    bool hasAlphaMask = false;
    byte[] alphaMask = hasAlpha ? new byte[width * height] : null;
    MonochromeMask mask = hasAlpha ?
      new MonochromeMask(width, height) : null;

    int nOffsetRead = 0;
    if (logicalComponents == 3)
    {
      for (int y = 0; y < height; ++y)
      {
        int nOffsetWrite = 3 * (height - 1 - y) * width;
        int nOffsetWriteAlpha = 0;
        if (hasAlpha)
        {
          mask.StartLine(y);
          nOffsetWriteAlpha = (height - 1 - y) * width;
        }

        for (int x = 0; x < width; ++x)
        {
          imageData[nOffsetWrite] = imageBits[nFileOffset + nOffsetRead + 2];
          imageData[nOffsetWrite + 1] = imageBits[nFileOffset + nOffsetRead + 1];
          imageData[nOffsetWrite + 2] = imageBits[nFileOffset + nOffsetRead];
          if (hasAlpha)
          {
            mask.AddPel(imageBits[nFileOffset + nOffsetRead + 3]);
            alphaMask[nOffsetWriteAlpha] = imageBits[nFileOffset + nOffsetRead + 3];
            if (!hasMask || !hasAlphaMask)
            {
              if (imageBits[nFileOffset + nOffsetRead + 3] != 255)
              {
                hasMask = true;
                if (imageBits[nFileOffset + nOffsetRead + 3] != 0)
                  hasAlphaMask = true;
              }
            }
            ++nOffsetWriteAlpha;
          }
          nOffsetRead += hasAlpha ? 4 : components;
          nOffsetWrite += 3;
        }
        nOffsetRead = 4 * ((nOffsetRead + 3) / 4); //Align to 32 bit boundary
      }
    }
    else if (components == 1)
    {
      //Grayscale
      throw new NotImplementedException("Image format not supported (grayscales).");
    }

    FlateDecode fd = new FlateDecode();
    if (hasMask)
    {
      //monochrome mask is either sufficient or
      //provided for compatibility with older reader versions
      byte[] maskDataCompressed = fd.Encode(mask.MaskData);
      PdfDictionary pdfMask = new PdfDictionary(document);
      pdfMask.Elements.SetName(Keys.Type, "/XObject");
      pdfMask.Elements.SetName(Keys.Subtype, "/Image");

      Owner.irefTable.Add(pdfMask);
      pdfMask.Stream = new PdfStream(maskDataCompressed, pdfMask);
      pdfMask.Elements[Keys.Length] = new PdfInteger(maskDataCompressed.Length);
      pdfMask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
      pdfMask.Elements[Keys.Width] = new PdfInteger(width);
      pdfMask.Elements[Keys.Height] = new PdfInteger(height);
      pdfMask.Elements[Keys.BitsPerComponent] = new PdfInteger(1);
      pdfMask.Elements[Keys.ImageMask] = new PdfBoolean(true);
      Elements[Keys.Mask] = pdfMask.Reference;
    }
    if (hasMask && hasAlphaMask && pdfVersion >= 14)
    {
      //The image provides an alpha mask (requires Arcrobat 5.0 or higher)
      byte[] alphaMaskCompressed = fd.Encode(alphaMask);
      PdfDictionary smask = new PdfDictionary(document);
      smask.Elements.SetName(Keys.Type, "/XObject");
      smask.Elements.SetName(Keys.Subtype, "/Image");

      Owner.irefTable.Add(smask);
      smask.Stream = new PdfStream(alphaMaskCompressed, smask);
      smask.Elements[Keys.Length] = new PdfInteger(alphaMaskCompressed.Length);
      smask.Elements[Keys.Filter] = new PdfName("/FlateDecode");
      smask.Elements[Keys.Width] = new PdfInteger(width);
      smask.Elements[Keys.Height] = new PdfInteger(height);
      smask.Elements[Keys.BitsPerComponent] = new PdfInteger(8);
      smask.Elements[Keys.ColorSpace] = new PdfName("/DeviceGray");
      Elements[Keys.SMask] = smask.Reference;
    }

    byte[] imageDataCompressed = fd.Encode(imageData);

    Stream = new PdfStream(imageDataCompressed, this);
    Elements[Keys.Length] = new PdfInteger(imageDataCompressed.Length);
    Elements[Keys.Filter] = new PdfName("/FlateDecode");
    Elements[Keys.Width] = new PdfInteger(width);
    Elements[Keys.Height] = new PdfInteger(height);
    Elements[Keys.BitsPerComponent] = new PdfInteger(8);
    //TODO: CMYK
    Elements[Keys.ColorSpace] = new PdfName("/DeviceRGB");
    if (image.Interpolate)
      Elements[Keys.Interpolate] = PdfBoolean.True;
  }
}
  • #1 Frage, sind Sie ordnungsgemäß zu entsorgen Ihre streams? Auch, möchten Sie vielleicht, um etwas von Ihrem code.
  • es gibt nichts zu Entsorgen ist, neben MemoryStream. Die wird geschlossen. Und als eine Angelegenheit von der Tat MemoryStream.Close() ist nur ein Aufruf an MemoryStream.Dispose(true), gefolgt von GC.SuppressFinalize(this). Byte-arrays sind nicht Einweg, so gibt es nichts mehr das ich tun kann. Wie für den code... es ist sehr Komplex und kommt von der PdfSharp lib. Es ist nicht mein code, aber ich versuche zu verstehen und die Probleme beheben, die es macht.
  • Ich war Lesung auf einige der Fragmentierung. Es scheint, dass auf 64-bit-windows, die zugrunde liegende Speicher-manager, sollten Sie nicht setzen dieses Verhalten. Ist es möglich, dass Ihr Prozess läuft im WOW64 -, d.h., dass Sie nur für x86 kompiliert? Ich aktualisiert meine Antwort mit mehr Informationen über die Fragmentierung Problem.
  • Ganz wenige Exemplare und Helfer-arrays, die Fliegen hier Rum. Dies könnte eine seltene Gelegenheit, aufrufen von GC.Collect() könnte helfen, am besten nach oder am Ende der ReadTrueColorMemoryBitmap().
  • Wir sind uns alle einig, dass das problem mit dem GC Versagen, sich zu erholen, oder fragmentiert, der verwaltete heap-Speicher. Dann, eine gute alternative sein könnte, mit nicht verwaltetem Speicher: System.IO.UnmanagedMemoryStream das problem ist Das man vorher wissen müssen der Platzbedarf. Oder zumindest eine Obergrenze. Die Dokumentation sagt ganz klar, dass dieser stream nicht reserviert Speicher auf dem heap. Ein weiteres problem, dein Programm braucht, Sicherheits-Einstellungen, die erlaubt, dies zu tun.
InformationsquelleAutor SiliconMind | 2012-03-27
Schreibe einen Kommentar