c# – OutOfMemoryException @ WriteableBitmap @后台代理

前端之家收集整理的这篇文章主要介绍了c# – OutOfMemoryException @ WriteableBitmap @后台代理前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个 Windows Phone 8应用程序,它使用后台代理:

>从互联网获取数据;
>基于用户控件生成图像,该控件使用步骤1中的数据作为数据源;
>在用户控件中我有Grid& StackPanel&一些文字和图像控件;
>当某些映像使用安装文件夹中的本地资源时(/ Assets / images / …)
我用作背景的其中一个是用户从手机的照片库中选择的,所以我必须使用C#代码来设置源代码.

但是,当它在后台运行时,它会得到OutOfMemoryException,到目前为止一些故障排除:

>当我在“前线”中运行该过程时,一切正常;
>如果我注释掉更新进度,并直接创建图像,它也可以正常工作;
>如果我没有设置背景图像,它也可以正常工作;
>在var bmp = new WriteableBitmap(480,800)期间抛出OutOfMemoryException;
我已经将图像尺寸从1280 * 768缩小到800 * 480,我认为它是全屏背景图像的底线,不是吗?
>经过一些研究,我发现出现这个问题是因为它超过了周期性任务的11 MB限制.
>我尝试使用DeviceStatus.ApplicationCurrentMemoryUsage来跟踪内存使用情况:

– 限制是11,534,336(位)

– 当后台代理启动时,即使没有任何任务,内存使用量也变为4,648,960

– 从互联网获得更新时,它增长到5,079,040

– 完成后,它回落到4,960

– 当调用开始时(从用户控件生成图像),它增长到8,499,200

好吧,我想这就是问题所在,通过WriteableBitmap呈现图像的内存很少.

知道如何解决这个问题吗?

有没有更好的方法用户控件/或其他任何东西生成图像?

实际上原始图像可能只有100 kb左右,但是,当通过WriteableBitmap进行渲染时,文件大小(以及我猜想的所需内存大小)可能会增长到1-2MB.

或者我可以从任何地方释放内存吗?

================================================== ============

顺便说一句,当这个Code Project article说我只能在周期性任务中使用11MB内存时;

但是,这个MSDN article表示我可以使用Windows Phone 8 Update 3最多20 MB或25 MB;
哪个是对的?为什么我处于第一种情况?

================================================== ============

编辑:

说到调试器,它也在MSDN article中说明:

在调试器下运行时,将暂停内存和超时限制.

但为什么我仍然会遇到限制?

================================================== ============

编辑:

好吧,我发现似乎有些帮助,我现在就检查一下,建议仍然受欢迎.

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,100);
        }
    }
}

ImageUserControl的XAML代码

<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...
}

解决方法

如果我注释掉更新进度,它也可以正常工作我认为你应该专注于那部分.它似乎表明更新后没有释放一些内存.在渲染图片之前,请确保更新过程中使用的所有引用都超出范围.强制垃圾收集也有帮助:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect(); // Frees the memory that was used by the finalizers

另一件需要考虑的事情是调试器也使用了大量内存.通过在“发布”模式下编译项目并在手机上部署以确保内存不足来进行真正的测试.

尽管如此,我已经处于这种状况,所以我知道这可能还不够.关键是:.NET Framework中的某些库是懒惰加载的.例如,如果您的更新过程涉及下载某些数据,则后台代理将加载网络库.这些库无法卸载,会浪费一些代理的内存.这就是为什么即使释放您在更新过程中使用的所有内存,也不会达到启动后台代理时所用的相同数量的可用内存.看到这一点,我在我的一个应用程序中所做的是跨两次执行跨越后台代理的工作量.基本上,代理执行时:

>如果要处理待处理数据,请检查隔离存储.如果没有,只需执行更新过程并将所有需要的数据存储在隔离存储中
>如果存在未决数据(即,在下一次执行中),则生成图片并清除数据

这意味着图片每小时只生成一次,而不是每30分钟生成一次,因此只有在其他一切都失败的情况下才使用此解决方法.

猜你在找的C#相关文章