我得到System.OutOfMemoryException。有一种方法可以让我的代码更轻松吗?

时间:2011-12-11 16:52:05

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

我想编写一个例程,从服务器(远程桌面)接收一些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;
    }

3 个答案:

答案 0 :(得分:2)

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


如果可能,您还应该重复使用内存流。这大大降低了气压很多。您正在分配许多大型对象,在这种情况下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()

后面

答案 1 :(得分:1)

一旦我编写了一个处理从文件加载的大量图像的程序。我尽快Dispose尽我所能,让其余的人留在GC。这还不够,内存使用情况分析显示GC相对于我的程序的图像加载速度来说太慢了。解决方案是每次处理完一定数量的图像时手动调用GC.Collect()。请注意this is not a good practice,但有时会有帮助。至少值得一试。

答案 2 :(得分:1)

问题可能与二进制协议错误有关(视频长度有些混乱,请参阅lBRVideo.ReadInt16和ReadInt32调用你注释掉)