内存泄漏-使用MemoryStream从尼康相机捕获实时视频

时间:2019-03-28 08:44:50

标签: c# wpf memorystream

我正在使用MemoryStream获取JPEGBuffer,然后使用JpegBitmapDecoder将其解码为Bitmap。每次我开始从Nikon Camera读取实时视频时,这都会导致内存使用量增加。

DispatchTimer刻度方法如下(每秒运行30次):

private void dispatcherTimer_Tick(object sender, EventArgs e) {
 if (isLiveVideoEnabled) {
  try {
   Nikon.NikonLiveViewImage liveImageFromCamera = ((MainWindow) myParent).currentDevice.GetLiveViewImage();

   using(var liveImageStream = new MemoryStream(liveImageFromCamera.JpegBuffer)) 
   {
    liveImageComponent.Source = BitmapFrame.Create(liveImageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);

    liveLoop.Set();
   }
  } catch (Nikon.NikonException ex) {
   MessageBox.Show(ex.Message);
  }
 }
}

这是用户按下Capture Button时的代码。我要停止实时显示,然后从尼康拍摄照片。

ImageBehavior.AddAnimationCompletedHandler(imageControl,  async (sender , e) => {
          // Disabling Live Stream
          await liveLoop.WaitAsync();
          isLiveVideoEnabled = false;
          (myParent as MainWindow).currentDevice.LiveViewEnabled = false;

          //Starting to Capture Photo
          await (myParent as MainWindow).capturePhoto();
          await (myParent as MainWindow).waitForTheImage();
          string path = (myParent as MainWindow).getPhotoPath();
          Console.WriteLine("********************     " + path + "      *********************");
          System.Windows.Media.Imaging.BitmapImage bImage = new BitmapImage(new Uri(path));
          ImageBehavior.SetAnimatedSource(imageControl, null);
          (sender as Image).Source = bImage;
          Photos.imageDictionary[imageNumber] = path;
          //Enabling the Live Stream

          isLiveVideoEnabled = true;
          currentImageControl = imageControl;
          stopLoading();
          showRetry();
          (myParent as MainWindow).currentDevice.LiveViewEnabled = true;
     });

此应用程序处于连续运行状态。

  1. 触摸屏捕获照片
  2. 实时显示开始,用户单击计数器上的GIF
  3. 一旦GIF动画周期完成,它将停止实时取景并捕获照片。
  4. 用户移至反馈部分,并在此处完成一个操作周期。

启动我的应用程序时,它以初始内存67MB开始。 “第一操作周期”将内存增加到185MB,并且每次启动实时显示页面时几乎都会添加130MB

首先,我认为问题出在WPF Pages上,但我仔细检查了“内存使用情况”,它仅在启动实时摄像头时才会增加。打开页面不会增加任何内存。

我认为我对MemoryStream使用了错误的方法。请指导。

更新1 [dispatcherTimer_Tick代码已更新]:

我通过在using(MemoryStream)方法内引入dispatcherTimer_Tick来实现了Clemens解决方案。并且还将BitmapImage之后的BitmapImage.EndInit()冻结,但是内存消耗是相同的,没有区别。

我在VS中启动了Profiler,并收集了以下信息,至少现在我正在研究应注意的事项。

我看到byte[] stream的初始图像仍处于连接状态,并且未被GC收集。

First Profiler Image

在那之后,我开始寻找进一步的方向。这是另一张图片。 (GetLiveViewImage来自nikoncswrapper

enter image description here

最后一个显示函数名称的图像:

enter image description here

现在我想我有更多信息可以解决这个问题。但是我不明白我还能做些什么。

我什至为getBitmapImage创建了一个新方法:

public BitmapImage getBitmapFromURI(Uri uri) {
 var image = new BitmapImage();
 image.BeginInit();
 image.CacheOption = BitmapCacheOption.OnLoad;
 image.UriSource = uri;
 image.EndInit();
 image.Freeze();
 System.GC.Collect();
 GC.WaitForPendingFinalizers();
 return image;
}

1 个答案:

答案 0 :(得分:1)

使用BitmapCacheOption.None,从流中解码的BitmapDecoder或BitmapFrame使流保持打开状态。

由于MemoryStream是IDisposable,因此应将其丢弃,最好通过在using声明中创建它来进行处置。但是,只有在通过设置BitmapCacheOption.OnLoad立即对图像进行解码的情况下才有可能。

您也不需要显式使用特定的BitmapDecoder。只需使用BitmapFrame.Create方法。它会自动选择合适的解码器。

using (var liveImageStream = new MemoryStream(liveImageFromCamera.JpegBuffer))
{
    liveImageComponent.Source = BitmapFrame.Create(
        liveImageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
    ...
}

如果仍然存在问题,您可以查看以下答案:https://stackoverflow.com/a/6271982/1136211(尽管afaik立即解码的BitmapFrame应该已经被冻结)。