我得到System.OutOfMemoryException.有一种方法可以使我的代码更轻

本文关键字:可以使 方法 一种 我的 代码 System OutOfMemoryException | 更新日期: 2023-09-27 18:17:25

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

我得到System.OutOfMemoryException.有一种方法可以使我的代码更轻

使用基于 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()后面

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

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

相关文章: