2011-12-11 86 views
0

我想写一个从服务器接收一些JPEG帧程序(远程桌面 - 等),将它们转换成位图图像,然后将它们显示在Windows窗体上。我试图让例程尽可能轻,但也许我做错了,因为我总是收到一个System.OutOfMemoryException。我的代码如下:我得到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; 
    } 
+0

看不到如果释放由lCurrent – imaximchuk

+0

豌豆用于提供dUpdateVideo的源存储器,它也可以是内存泄漏的来源。 查看是否收到了在lVideoLength(也可能是非常大的数字,由于一些错误) – imaximchuk

+1

我觉得这是你的二进制协议和视频长度的问题以某种方式搞砸了(见lBRVideo.ReadInt16和ReadInt32叫你注释掉正确的数据) – imaximchuk

回答

2

当你使用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()

+0

感谢您的提示:) – gc5

+0

再次感谢您的努力:) – gc5

1

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

+0

我忘了那个功能,谢谢:)是的,这不是一个好习惯,但也许在这里这是必要的 – gc5

1

的问题可能与二进制协议错误(视频长度以某种方式搞砸了,看到lBRVideo.ReadInt16和ReadInt32叫你注释掉)

相关问题