我有一个Windows Phone 8应用程序,它使用后台代理:
然而,当它在后台运行时,它会得到OutOfMemoryException
,到目前为止进行了一些故障排除:
OutOfMemoryException
期间var bmp = new WriteableBitmap(480, 800);
被抛弃了
我已经将图像尺寸从1280 * 768缩小到800 * 480,我认为它是全屏背景图像的底线,不是吗?我尝试使用DeviceStatus.ApplicationCurrentMemoryUsage
来跟踪内存使用情况:
- 限制是11,534,336(位)
- 当后台代理启动时,即使没有任何任务,内存使用量也变为4,648,960
- 从互联网获取更新时,它增长到5,079,040
- 完成后,它回落到4,648,960
- 当调用开始时(从用户控件生成图像),它长大到8,499,200
嗯,我猜这就是问题所在,通过WriteableBitmap
呈现图片的内存很少。
知道如何解决这个问题吗?
是否有更好的方法从用户控件/或其他任何内容生成图像?
实际上原始图像可能只有100 kb左右,但是,当按WriteableBitmap
渲染时,文件大小(以及我猜想的所需内存大小)可能会增长到1-2MB。
或者我可以从任何地方释放内存吗?
=============================================== ===============
BTW,当这个Code Project article说我在周期性任务中只能使用11MB内存时;
但是,MSDN article表示我可以使用Windows Phone 8 Update 3最多20 MB或25 MB; 哪个是对的?为什么我处于第一种情况?
=============================================== ===============
编辑:
说到调试器,它也在MSDN article中说明:
When running under the debugger, memory and timeout restrictions are suspended.
但为什么我仍然会遇到限制?
=============================================== ===============
编辑:
好吧,我发现似乎有些帮助,我现在会检查它们,建议仍然受欢迎。
http://writeablebitmapex.codeplex.com/
http://suchan.cz/2012/07/pro-live-tiles-for-windows-phone/
http://notebookheavy.com/2011/12/06/microsoft-style-dynamic-tiles-for-windows-phone-mango/
=============================================== ===============
生成图片的代码:
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var customBG = new ImageUserControl();
customBG.Measure(new Size(480, 800));
var bmp = new WriteableBitmap(480, 800); //Thrown the **OutOfMemoryException**
bmp.Render(customBG, null);
bmp.Invalidate();
using (var isf = IsolatedStorageFile.GetUserStoreForApplication())
{
filename = "/Shared/NewBackGround.jpg";
using (var stream = isf.OpenFile(filename, System.IO.FileMode.OpenOrCreate))
{
bmp.SaveJpeg(stream, 480, 800, 0, 100);
}
}
}
ImageUserControl
:
<UserControl blabla... d:DesignHeight="800" d:DesignWidth="480">
<Grid x:Name="LayoutRoot">
<Image x:Name="nBackgroundSource" Stretch="UniformToFill"/>
//blabla...
</Grid>
</UserControl>
ImageUserControl
后面的C#代码:
public ImageUserControl()
{
InitializeComponent();
LupdateUI();
}
public void LupdateUI()
{
DataInfo _dataInfo = new DataInfo();
LayoutRoot.DataContext = _dataInfo;
try
{
using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var isoFileStream = isoStore.OpenFile("/Shared/BackgroundImage.jpg", FileMode.Open, FileAccess.Read))
{
BitmapImage bi = new BitmapImage();
bi.SetSource(isoFileStream);
nBackgroundSource.Source = bi;
}
}
}
catch (Exception) { }
}
DataInfo
是settings page中保存数据的另一个类来自互联网:
public class DataInfo
{
public string Wind1 { get { return GetValueOrDefault<string>("Wind1", "N/A"); } set { if (AddOrUpdateValue("Wind1", value)) { Save(); } } }
public string Wind2 { get { return GetValueOrDefault<string>("Wind2", "N/A"); } set { if (AddOrUpdateValue("Wind2", value)) { Save(); } } }
//blabla...
}
答案 0 :(得分:1)
If I comment out the update progress, and create the image directly, it also works fine
我认为你应该专注于那部分。它似乎表明更新后没有释放一些内存。在渲染图片之前,请确保更新过程中使用的所有引用都超出范围。强制垃圾收集也有帮助:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect(); // Frees the memory that was used by the finalizers
另一件需要考虑的事情是调试器也在使用大量内存。通过在“发布”模式下编译项目并在手机上部署以确保内存不足来进行真正的测试。
尽管如此,我已经处于这种状况,所以我知道这可能还不够。关键是:.NET Framework中的某些库是懒惰加载的。例如,如果更新过程涉及下载某些数据,则后台代理将加载网络库。这些库无法卸载,会浪费一些代理的内存。这就是为什么,即使释放在更新过程中使用的所有内存,也不会达到启动后台代理时所用的相同数量的可用内存。看到这一点,我在我的一个应用程序中所做的是跨两次执行跨越后台代理的工作量。基本上,当代理执行时:
这意味着图片每小时只生成一次,而不是每30分钟生成一次,所以只有在其他一切都失败时才使用此解决方法。
答案 1 :(得分:1)
较大的内存限制适用于后台音频代理,它在文档中明确指出。你坚持使用11 MB,当你在后台尝试使用智能手机时,这真的很痛苦。
480x800为你的内存增加了一个MB,因为每个像素需要4个字节,所以最后它大约是1.22MB。当用JPEG压缩时,那么是 - 它只有大约100KB才有意义。但无论何时使用WriteableBitmap,它都会被加载到内存中。
在另一个答案中提到的强制GC.Collect之前你可以尝试的其中一件事就是在它们超出范围之前将其归零 - 无论是BitmapImage还是WriteableBitmap。除此之外,您可以尝试以编程方式从网格中删除Image对象,并将其设置为null。
你有没有向我们展示任何其他的WriteableBitmap,BitmapImage或Image对象?
另外,请尝试不使用调试器。我已经阅读了某个地方,它增加了另外1-2MB,当你只有11 MB时,它会很多。虽然,如果它与调试器一起快速崩溃,即使它在没有调试器的情况下突然接合,我也不会冒险。但是出于测试目的,你可以试一试。
您需要使用ImageUserControl吗?您是否可以尝试逐步创建图像和所有其他对象,而不使用XAML,这样您就可以在每个步骤中测量内存以查看它在哪个点穿过屋顶?