【问题标题】:I get System.OutOfMemoryException. There is a way to make my code lighter?我得到 System.OutOfMemoryException。有办法让我的代码更轻吗?
【发布时间】:2011-12-11 16:52:04
【问题描述】:

我想编写一个例程,从服务器(远程桌面 - 类似)接收一些 jpeg 帧,将它们转换为位图图像,然后在 Windows 窗体上显示它们。我试图使例程尽可能轻松,但也许我做错了,因为我总是收到 System.OutOfMemoryException。我的代码如下:

编辑:添加了与此异常相关的部分

private void WatcherRoutine()
    {
        Boolean lLoopEnd = false;
        Bitmap lCurrent = null;
        //Graphics lGraphics = null;
        Image lImg = null;
        BinaryReader lBRVideo = new BinaryReader(this._state.Video.GetStream());

        while (lLoopEnd == false)
        {
            try
            {
                // Reads frame type
                switch (lBRVideo.ReadByte())
                {
                    // Frame received is a big frame (ie a desktop screenshot)
                    case Constants.BIGFRAME:
                        {
                            // Reads frame size in bytes
                            Int32 lVideoLength = lBRVideo.ReadInt32();
                            if (lVideoLength > 0)
                            {
                                // Stores frame in a stream
                                MemoryStream ms = new MemoryStream(lBRVideo.ReadBytes(lVideoLength));
                                // Creates image from stream
                                lImg = Image.FromStream(ms);
                                ms.Dispose();
                                // Creates bitmap from image
                                lCurrent = new Bitmap(lImg);
                                lImg.Dispose();
                                // Passes image to windows form to display it
                                this.Invoke(this._state.dUpdateVideo, lCurrent);
                                    ////lGraphics = Graphics.FromImage(lImg);
                                    //lGraphics.Dispose();
                            }
                        }
                        break;
                    // Diff frame (ie a small part of desktop that has changed)
                    // Commenting this part makes the exception disappear :|
                    case Constants.DIFFFRAME:
                        {
                            Int16 lX = lBRVideo.ReadInt16(),
                                lY = lBRVideo.ReadInt16();
                            Int32 lVideoLength = lBRVideo.ReadInt32();
                            if (lVideoLength > 0)
                            {
                                //Byte[] lVideoImg = lBRVideo.ReadBytes(lVideoLength);
                                //Image lImgDiff = Image.FromStream(new MemoryStream(lVideoImg));
                                ////if(lGraphics != null)
                                //{
                                //    lGraphics.DrawImage(lImgDiff, lX, lY);
                                //    this.Invoke(this._state.dUpdateVideo, new Bitmap(lImg));
                                //}
                            }
                        }
                        break;
                    case Constants.CURSOR:
                        {
                            Int16 lX = lBRVideo.ReadInt16(),
                                lY = lBRVideo.ReadInt16();
                            // TODO
                        }
                        break;
                    default:
                        break;
                }
            }
            catch (Exception e)
            {
                if (this._state.WorkEnd == false)
                {
                    this._state.WorkEnd = true;
                    this.BeginInvoke(this._state.dDisconnect);
                }
                lLoopEnd = true;
                SmartDebug.DWL(e.Message);
            }
        }
    }

dUpdateVideo 是一个包含这个小例程的委托。也许我要释放 pBmp?

private void UpdateVideo(Bitmap pBmp)
    {
        this.VideoPictureBox.Image = pBmp;
    }

【问题讨论】:

  • 不查看是否释放 lCurrent 使用的内存
  • 请提供dUpdateVideo的来源,也可能是内存泄漏的来源。检查您是否在 lVideoLength 中收到正确的数据(由于某些错误,它可能是非常大的数字)
  • 我认为这是您的二进制协议的问题,并且视频长度有些混乱(请参阅 lBRVideo.ReadInt16 和 ReadInt32 调用您注释掉)
  • 现在我会检查一下 :) 编辑:我发现了一个错误..现在我会尝试看看它是否相关..
  • 它是相关的..如果你添加一个答案我会给你另一点,因为它是问题的一部分:) 谢谢你

标签: c# windows image bitmap out-of-memory


【解决方案1】:

当您使用基于 GDI+ 的 API (System.Drawing) 时,OutOfMemory 异常并不一定意味着您的内存不足。这也可能意味着传递给 GDI+ 的参数无效,或其他原因。 GDI+ 很漂亮OutOfMemory 开心。


如果可能,您还应该重用您的内存流。这降低了 GC 压力很多。您分配了许多大对象,在这种情况下 GC 非常糟糕。


另外我认为你永远不会处理lCurrent


那你就违反了Image.FromStream的合约:

您必须在图像的生命周期内保持流打开:

lImg = Image.FromStream(ms);
ms.Dispose();
lCurrent = new Bitmap(lImg);// `lImage` is used here, but `ms` is already disposed
lImg.Dispose();

Image.FromStream 的文档指出:

您必须在图像的生命周期内保持流打开。

ms.Dispose() 移到lImg.Dispose() 后面

【讨论】:

  • 再次感谢您的努力:)
【解决方案2】:

有一次我写了一个程序来处理从文件中加载的大量图像。我Disposed 尽我所能,尽快,把剩下的交给 GC。这还不够,内存使用分析清楚地表明 GC 相对于我的程序的图像加载速度太慢了。解决方案是每次处理完给定数量的图像时手动调用GC.Collect()。请注意this is not a good practice,但有时会有所帮助。至少值得一试。

【讨论】:

  • 我忘记了这个功能,谢谢 :) 是的,这不是一个好习惯,但也许这里是必要的
【解决方案3】:

问题可能与二进制协议错误有关(视频长度不知何故搞砸了,请参阅 lBRVideo.ReadInt16 和 ReadInt32 调用你注释掉)

【讨论】:

    猜你喜欢
    • 2018-10-05
    • 1970-01-01
    • 2021-10-13
    • 2013-07-16
    • 2022-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-05
    相关资源
    最近更新 更多