title: OutOfMemoryException when creating multiple byte arrays
body: <p>I'm constantly hitting an <code>OutOfMemoryException</code> inside a method that creates and processes some byte arrays. The code looks like this:</p>
  
  <ol>
  <li>Create MemoryStream to get some data (about 60MB).</li>
  <li>Create byte array (same size as MemoryStream, about 60MB)</li>
  <li>Fill the array with bytes from memory stream</li>
  <li>Close MemoryStream</li>
  <li>Process data from byte array</li>
  <li>Leave method</li>
  </ol>
  
  <p>When this method is called like 20-30 times I get <code>OutOfMemoryException</code> right where the byte array is allocated. But I don't think it's the system memory issue. Application memory usage is around 500MB (private working set) and the test machine is 64-bit with 4GB of RAM.</p>
  
  <p>Is it possible that memory used by the byte array or <code>MemoryStream</code> is not released after method finishes? But then, it does not look like this memory is allocated for the process as private working set is only 500MB or so.</p>
  
  <p>What may cause the <code>OutOfMemoryException</code> when creating large byte array (60MB) beside physical memory shortage?</p>
  
  <p><strong>[Edited to add code sample]</strong>
  Source comes from <a href="http://pdfsharp.net" rel="noreferrer">PdfSharp lib</a></p>
  
  <p>Exception is thrown at line <code>byte[] imageBits = new byte[streamLength];</code> It indeed looks like LOH fragmentation issue.</p>
  
  <pre><code>/// &lt;summary&gt;
  /// Reads images that are returned from GDI+ without color palette.
  /// &lt;/summary&gt;
  /// &lt;param name="components"&gt;4 (32bpp RGB), 3 (24bpp RGB, 32bpp ARGB)&lt;/param&gt;
  /// &lt;param name="bits"&gt;8&lt;/param&gt;
  /// &lt;param name="hasAlpha"&gt;true (ARGB), false (RGB)&lt;/param&gt;
  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 &gt; 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 &amp;&amp; ReadWord(imageBits, 28) != components * bits ||
         hasAlpha &amp;&amp; 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 &lt; 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 &lt; 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 &amp;&amp; hasAlphaMask &amp;&amp; pdfVersion &gt;= 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;
    }
  }
  </code></pre>