我正在使用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;
});
此应用程序处于连续操作状态。
当我启动我的应用程序时,它从最初的内存67MB
开始。第一个操作周期将内存增加到185MB
,每次启动实时视图页面时都会添加几乎130MB
。
首先我认为问题是关于WPF Pages
,但我仔细检查了内存使用情况,它只在我们启动实时相机时增加。打开页面不会增加任何内存。
我认为我对MemoryStream
使用了错误的方法。请指导。
更新1 [dispatcherTimer_Tick
代码更新]:
我通过在using(MemoryStream)
方法中引入dispatcherTimer_Tick
来实现Clemens解决方案。并且在BitmapImage
之后也冻结了BitmapImage.EndInit()
但是内存消耗是相同的并且没有区别。
我在VS中启动了Profiler并收集了以下信息,至少现在我正在研究我应该关注的事情。
初始图像,我看到byte[] stream
仍然连接,并没有被GC收集。
在那之后,我开始进一步寻找它的领先地位。这是另一张图片。 (GetLiveViewImage
来自nikoncswrapper
)
最后一张显示功能名称的图片:
现在我想我有更多的信息来解决这个问题。但我无法理解我还能做些什么。
我甚至为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;
}
使用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)。