OutOfMemoryException异常创建多个字节数组时多个、数组、字节、异常

2023-09-04 10:02:03 作者:最美的痕迹叫回忆√

我经常打一个 OutOfMemoryException异常创建和处理一些字节数组的方法中。在code是这样的:

创建的MemoryStream得到一些数据(约60MB)。 创建字节数组(大小相同的MemoryStream,约60MB) 从内存流字节填充数组 关闭的MemoryStream 从字节数组处理数据 将方法

在这里的字节数组被分配当这个方法被称为像20-30倍,我得到 OutOfMemoryException异常的权利。但我不认为这是系统内存的问题。应用程序的内存使用量大约是500MB(私人工作集)和测试机器是64位4GB的内存。

是否有可能使用的字节数组的内存或的MemoryStream 方法完成后没有释放?不过,它看起来并不像被分配给进程私有工作组此内存只有500MB左右。

什么可能导致 OutOfMemoryException异常创建大型的字节数组(60MB)的物理内存不足时,旁边?

源来自 PdfSharp LIB

抛出异常的行字节[] imageBits =新的字节[streamLength]; 这的确看起来像蕙碎片问题

  ///<总结>
///读取由GDI +不调色板返回图像。
///< /总结>
///< PARAM NAME =组件→4(32bpp的RGB),3(24 bpp的RGB,32bpp的ARGB)LT; /参数>
///< PARAM NAME =位> 8示/参数>
///< PARAM NAME =hasAlpha>真(ARGB),假(RGB)< /参数>
私人无效ReadTrueColorMemoryBitmap(INT组件,INT位,布尔hasAlpha)
{
  INT pdfVersion = Owner.Version;
  MemoryStream的内存=新的MemoryStream();
  image.gdiImage.Save(存储器,ImageFormat.Bmp);
  INT streamLength =(INT)memory.Length;

  如果(streamLength大于0)
  {
    byte []的imageBits =新的字节[streamLength]
    memory.Seek(0,SeekOrigin.Begin);
    memory.Read(imageBits,0,streamLength);
    memory.Close();

    INT高= image.PixelHeight;
    INT宽度= image.PixelWidth;

    如果(ReadWord(imageBits,0)!= ||覆盖0x4D42 //BM
        ReadDWord(imageBits,2)!= streamLength ||
        ReadDWord(imageBits,14)!= 40 || // sizeof的BITMAPINFOHEADER
        ReadDWord(imageBits,18)!=宽度||
        ReadDWord(imageBits,22)!=高)
    {
      抛出新的NotImplementedException(ReadTrueColorMemoryBitmap:不支持的格式);
    }
    如果(ReadWord(imageBits,26)!= 1 ||
      (hasAlpha&安培;!&安培;!ReadWord(imageBits,28)=组件*位||
       hasAlpha&功放;&安培; ReadWord(imageBits,28)!=(部件+ 1)*位)||
      ReadDWord(imageBits,30)!= 0)
    {
      抛出新的NotImplementedException(ReadTrueColorMemoryBitmap:不支持的格式#2);
    }

    INT nFileOffset = ReadDWord(imageBits,10);
    INT logicalComponents =组件;
    如果(组件== 4)
      logicalComponents = 3;

    byte []的为imageData =新的字节[组件*宽*高]。

    布尔hasMask = FALSE;
    布尔hasAlphaMask = FALSE;
    byte []的alphaMask = hasAlpha?新的字节[宽*高]:空;
    MonochromeMask面膜= hasAlpha?
      新MonochromeMask(宽,高):空;

    INT nOffsetRead = 0;
    如果(logicalComponents == 3)
    {
      对于(INT Y = 0; Y<高度; ++ Y)
      {
        INT nOffsetWrite = 3 *(高 -  1  -  Y)*宽;
        INT nOffsetWriteAlpha = 0;
        如果(hasAlpha)
        {
          mask.StartLine(Y);
          nOffsetWriteAlpha =(身高 -  1  -  Y)*宽;
        }

        对于(INT X = 0,X<宽度; ++ x)
        {
          为imageData [nOffsetWrite] = imageBits [nFileOffset + nOffsetRead + 2];
          为imageData [nOffsetWrite + 1] = imageBits [nFileOffset + nOffsetRead + 1];
          为imageData [nOffsetWrite + 2] = imageBits [nFileOffset + nOffsetRead];
          如果(hasAlpha)
          {
            mask.AddPel(imageBits [nFileOffset + nOffsetRead + 3]);
            alphaMask [nOffsetWriteAlpha] = imageBits [nFileOffset + nOffsetRead + 3];
            如果(!hasMask ||!hasAlphaMask)
            {
              如果(imageBits [nFileOffset + nOffsetRead + 3]!= 255)
              {
                hasMask = TRUE;
                如果(imageBits [nFileOffset + nOffsetRead + 3]!= 0)
                  hasAlphaMask = TRUE;
              }
            }
            ++ nOffsetWriteAlpha;
          }
          nOffsetRead + = hasAlpha? 4:组件;
          nOffsetWrite + = 3;
        }
        nOffsetRead = 4 *((nOffsetRead + 3)/ 4); //对齐到32位边界
      }
    }
    否则,如果(组件== 1)
    {
      //灰度
      抛出新的NotImplementedException(不支持的图像格式(灰度)。);
    }

    FlateDe code FD =新FlateDe code();
    如果(hasMask)
    {
      //单色面膜或者是不足或
      //提供了兼容老版本的阅读器
      byte []的maskDataCom pressed = fd.En code(mask.MaskData);
      PdfDictionary pdfMask =新PdfDictionary(文件);
      pdfMask.Elements.SetName(Keys.Type,/了XObject);
      pdfMask.Elements.SetName(Keys.Subtype,/图片);

      Owner.irefTable.Add(pdfMask);
      pdfMask.Stream =新PdfStream(maskDataCom pressed,pdfMask);
      pdfMask.Elements [Keys.Length] =新PdfInteger(maskDataCom pressed.Length);
      pdfMask.Elements [Keys.Filter] =新PdfName(/ FlateDe code);
      pdfMask.Elements [Keys.Width] =新PdfInteger(宽);
      pdfMask.Elements [Keys.Height] =新PdfInteger(高度);
      pdfMask.Elements [Keys.BitsPerComponent] =新PdfInteger(1);
      pdfMask.Elements [Keys.ImageMask] =新PdfBoolean(真正的);
      元素[Keys.Mask] = pdfMask.Reference;
    }
    如果(hasMask&安培;&安培; hasAlphaMask和放大器;&安培; pdfVersion> = 14)
    {
      //图像提供了一个alpha遮罩(要求Arcrobat 5.0或更高版本)
      byte []的alphaMaskCom pressed = fd.En code(alphaMask);
      PdfDictionary smask =新PdfDictionary(文件);
      smask.Elements.SetName(Keys.Type,/了XObject);
      smask.Elements.SetName(Keys.Subtype,/图片);

      Owner.irefTable.Add(smask);
      smask.Stream =新PdfStream(alphaMaskCom pressed,smask);
      smask.Elements [Keys.Length] =新PdfInteger(alphaMaskCom pressed.Length);
      smask.Elements [Keys.Filter] =新PdfName(/ FlateDe code);
      smask.Elements [Keys.Width] =新PdfInteger(宽);
      smask.Elements [Keys.Height] =新PdfInteger(高度);
      smask.Elements [Keys.BitsPerComponent] =新PdfInteger(8);
      smask.Elements [Keys.ColorSpace] =新PdfName(/ DeviceGray);
      元素[Keys.SMask] = smask.Reference;
    }

    byte []的imageDataCom pressed = fd.En code(为imageData);

    流=新PdfStream(imageDataCom pressed,这一点);
    元素[Keys.Length] =新PdfInteger(imageDataCom pressed.Length);
    元素[Keys.Filter] =新PdfName(/ FlateDe code);
    元素[Keys.Width] =新PdfInteger(宽);
    元素[Keys.Height] =新PdfInteger(高度);
    元素[Keys.BitsPerComponent] =新PdfInteger(8);
    // TODO:CMYK
    元素[Keys.ColorSpace] =新PdfName(/ DeviceRGB);
    如果(image.Interpolate)
      元素[Keys.Interpolate] = PdfBoolean.True;
  }
}
 

解决方案

我希望您使用 MemoryStream.GetBuffer()键,你是不是复制到一个新的数组

您的主要问题是没有直接的内存不足的蕙但碎片。这可以是一个棘手的问题,主要的问题是分配不同大小的大的缓冲区。被收集在蕙项,但不板结。

解决方案可能是:

首先要确保你没有阻止被收集什么。使用一个分析器。 尝试重用你的缓冲区中。 轮拨款的最多,以一组固定的数字。

最后2都需要你用超大阵列工作,可能需要一些工作。

实战 OutOfMemoryError异常

I'm constantly hitting an OutOfMemoryException inside a method that creates and processes some byte arrays. The code looks like this:

Create MemoryStream to get some data (about 60MB). Create byte array (same size as MemoryStream, about 60MB) Fill the array with bytes from memory stream Close MemoryStream Process data from byte array Leave method

When this method is called like 20-30 times I get OutOfMemoryException 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.

Is it possible that memory used by the byte array or MemoryStream 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.

What may cause the OutOfMemoryException when creating large byte array (60MB) beside physical memory shortage?

[Edited to add code sample] Source comes from PdfSharp lib

Exception is thrown at line byte[] imageBits = new byte[streamLength]; It indeed looks like LOH fragmentation issue.

/// <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;
  }
}

解决方案

I hope you are using MemoryStream.GetBuffer() and that you are not copying to a new array.

Your main problem is not a direct lack of memory but fragmentation of the LOH. That can be a tricky problem, the main issue is allocating large buffers of varying size. Items on the LOH are collected but not compacted.

Solutions might be:

first make sure you are not blocking anything from being collected. use a profiler. try to reuse your buffer(s). round allocations up to a set of fixed numbers.

The last 2 both require you to work with oversized arrays, may take some work.