内存泄漏 - 使用MemoryStream从Nikon Camera捕获实时视频

问题描述 投票:2回答:1

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

DispatchTimer tick方法如下(每秒运行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;
}
c# wpf memorystream
1个回答
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)。

© www.soinside.com 2019 - 2024. All rights reserved.