我正在使用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;
});
此应用程序处于连续运行状态。
启动我的应用程序时,它以初始内存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;
}
答案 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应该已经被冻结)。