我得到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;
}
使用基于 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 调用您注释掉(