C# 内存泄漏-使用MemoryStream从尼康摄像头捕获实时视频
我正在使用C# 内存泄漏-使用MemoryStream从尼康摄像头捕获实时视频,c#,wpf,memorystream,C#,Wpf,Memorystream,我正在使用MemoryStream获取JPEGBuffer,然后使用JpegBitmapDecoder将其解码为位图。这导致每次我开始阅读尼康摄像头的实时视频时,内存使用量都会增加 DispatchTimertick方法写在下面(每秒运行30次): private void dispatchermer_Tick(对象发送方,事件参数e){ 如果(isLiveVideoEnabled){ 试一试{ Nikon.NikonLiveViewImage liveImageFromCamera=((主窗口
MemoryStream
获取JPEGBuffer,然后使用JpegBitmapDecoder
将其解码为位图。这导致每次我开始阅读尼康摄像头的实时视频时,内存使用量都会增加
DispatchTimer
tick方法写在下面(每秒运行30次):
private void dispatchermer_Tick(对象发送方,事件参数e){
如果(isLiveVideoEnabled){
试一试{
Nikon.NikonLiveViewImage liveImageFromCamera=((主窗口)myParent).currentDevice.GetLiveViewImage();
使用(var liveImageStream=newmemoryStream(liveImageFromCamera.JpegBuffer))
{
liveImageComponent.Source=BitmapFrame.Create(liveImageStream,BitmapCreateOptions.None,BitmapCacheOption.OnLoad);
liveLoop.Set();
}
}捕获(尼康,尼康例外){
MessageBox.Show(例如Message);
}
}
}
这是用户按下捕获按钮时的代码。我正在停止实况转播,然后从尼康那里抓拍照片
ImageBehavior.AddAnimationCompletedHandler(imageControl,异步(发送方,e)=>{
//禁用实时流
wait liveLoop.WaitAsync();
isLiveVideoEnabled=false;
(myParent作为主窗口)。currentDevice.LiveViewEnabled=false;
//开始抓拍照片
等待(myParent作为主窗口)。capturePhoto();
wait(作为主窗口的myParent).waitForTheImage();
字符串路径=(myParent作为主窗口).getPhotoPath();
Console.WriteLine(“**********************”+路径+“**********************”);
System.Windows.Media.Imaging.BitmapImage bImage=新BitmapImage(新Uri(路径));
SetAnimatedSource(imageControl,null);
(发送方为图像)。源=双图像;
Photos.imageDictionary[imageNumber]=路径;
//启用实时流
isLiveVideoEnabled=true;
currentImageControl=imageControl;
停止加载();
showRetry();
(myParent作为主窗口)。currentDevice.LiveViewEnabled=true;
});
此应用程序处于连续运行状态
67MB
。
第一个操作周期将内存增加到185MB
,并且每次启动Live View页面时几乎都会添加130MB
首先,我认为问题在于WPF页面
,但我仔细检查了内存使用情况,只有当我们启动live camera时,内存使用才会增加。打开页面不会增加任何内存
我想我对MemoryStream
使用了错误的方法。请导游
更新1[Dispatchermer\u勾选
代码已更新]:
我通过在Dispatchermer\u Tick
方法中引入使用(MemoryStream)
实现了Clemens解决方案。并且在BitmapImage.EndInit()
之后冻结BitmapImage
,但是内存消耗是相同的,没有区别
我在VS中启动了Profiler并收集了以下信息,至少现在我看到了我应该注意的事情
我看到的byte[]stream
的初始图像仍然是连接的,并且没有被GC收集
从那以后,我开始寻找更进一步的方向。这是另一张图片。(GetLiveViewImage
来自NikonSwraper
)
最后一幅显示函数名的图像:
现在我想我有更多的信息来解决这个问题。但我无法理解我还能做什么
我甚至创建了一个新方法来getBitmapImage
:
公共位图图像getBitmapFromURI(Uri){
var image=新的位图图像();
image.BeginInit();
image.CacheOption=BitmapCacheOption.OnLoad;
image.UriSource=uri;
image.EndInit();
image.Freeze();
System.GC.Collect();
GC.WaitForPendingFinalizers();
返回图像;
}
使用BitmapCacheOption。无
从流解码的BitmapDecoder或BitmapFrame使流保持打开状态
由于MemoryStream是一个IDisposable
,因此最好通过在using声明中创建它来处理它。但是,只有通过设置BitmapCacheOption.OnLoad
立即解码图像时,才可能执行此操作
您也不需要显式使用特定的位图解码器。只需使用BitmapFrame.Create
方法即可。它会自动选择合适的解码器
using (var liveImageStream = new MemoryStream(liveImageFromCamera.JpegBuffer))
{
liveImageComponent.Source = BitmapFrame.Create(
liveImageStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
...
}
如果仍然存在问题,您可以查看以下答案:(虽然立即解码的位图帧应该已经冻结)。您从未关闭并处理过流,您可以选择,但将其放入USE将以最简单的方式解决大部分问题。注意,
如果(liveImageStream!=null)
是没有意义的。您不需要检查new
运算符的结果是否为null。但是,在未检查其结果是否为null的情况下,不能使用as
运算符,就像在(myParent as MainWindow).currentDevice.GetLiveViewImage()
中所做的那样。这实际上应该是((MainWindow)myParent).currentDevice.GetLiveViewImage()
。虽然当不再需要IDisPobles时,处理IDisPobles是一个好习惯,但对于内存流来说,这是不必要的。它不拥有任何可使用的资源,在处理时也不会释放内存。不过,这是一个好习惯,因为您可能最终会将内存流
换成另一个需要处理的内存流。