WriteableBitmap上发生OutOfMemoryException

时间:2013-07-30 12:48:45

标签: c# windows-phone-7 windows-phone-8 bitmapimage

我正在开发一个Windows手机应用程序,可用于将图像上传到Web服务器。我正在从设备中选择所有图像到一个列表对象。我将所有位图图像逐个转换为byte []。

我的代码

public byte[] ConvertToBytes(BitmapImage bitmapImage)
    {
        byte[] data = null;
        WriteableBitmap wBitmap = null;

        using (MemoryStream stream = new MemoryStream())
        {
            wBitmap = new WriteableBitmap(bitmapImage);
            wBitmap.SaveJpeg(stream, wBitmap.PixelWidth, wBitmap.PixelHeight, 0, 100);
            stream.Seek(0, SeekOrigin.Begin);
            //data = stream.GetBuffer();
            data = stream.ToArray();
            DisposeImage(bitmapImage);
            return data;
        }

    }
    public void DisposeImage(BitmapImage image)
    {
        if (image != null)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream(new byte[] { 0x0 }))
                {
                    image.SetSource(ms);
                }
            }
            catch (Exception ex)
            {
            }
        }
    }

从位图转换为字节

 using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (!store.DirectoryExists("ImagesZipFolder"))
            {
                //MediaImage mediaImage = new MediaImage();
                //mediaImage.ImageFile = decodeImage(new byte[imgStream[0].Length]);
                //lstImages.Items.Add(mediaImage);

                store.CreateDirectory("ImagesZipFolder");
                for (int i = 0; i < imgname.Count(); i++)
                {
                    using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(@"ImagesZipFolder\" + imgname[i], FileMode.CreateNew,store))
                    //using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(@"ImagesZipFolder\text.txt" , System.IO.FileMode.OpenOrCreate, store))                        
                    {
                       // byte[] bytes = new byte[imgStream[i].Length];
                        byte[] bytes = ConvertToBytes(ImgCollection[i]);
                        stream.Write(bytes, 0, bytes.Length);
                    }
                }
            }
            else {
                directory = true;
            }
          }

我的模拟器中有91张图片。当我将所有这些位图图像转换为 byte [] 时,在wBitmap = new WriteableBitmap(bitmapImage);行上出现以下错误

  

System.Windows.ni.dll中出现“System.OutOfMemoryException”类型的异常,但未在用户代码中处理

Error

我该怎么做才能解决这个错误?

网络服务

如果我们向Web服务发送大量文件,是否会出现错误,如

  

System.ServiceModel.ni.dll中出现“System.OutOfMemoryException”类型的异常,但未在用户代码中处理

3 个答案:

答案 0 :(得分:2)

  

我该怎么做才能解决这个错误?

改变你做事的方式,减少记忆。

例如,不是转换每张图片然后上传它们,转换图片,上传图片,转换下一张图片,等等。

如果您真的想一次处理所有图片,可以将字节数组存储在隔离的存储中,而不是将它们保存在内存中,并在需要时将其读回。

基本上,重新考虑您的过程并使用存储在给定时间使用更少的内存。

或者要求微软取消Windows Phone的内存限制,但这可能有点棘手。

答案 1 :(得分:1)

问题在于GC和位图图像如何一起工作,如本错误报告中所述:https://connect.microsoft.com/VisualStudio/feedback/details/679802/catastrophic-failure-exception-thrown-after-loading-too-many-bitmapimage-objects-from-a-stream#details

来自报告:

  

当Silverlight加载图像时,框架会保留引用和   缓存解码图像,直到流控制返回到UI   线程调度员。当你像这样紧紧地加载图像时,   即使您的应用程序没有保留引用,GC也不能   释放图像,直到我们在流量控制时释放我们的参考   返回。

     

处理完20张左右的图像后,您可以停止并排队下一张图像   使用Dispatcher.BeginInvoke设置只是为了分解工作   一批处理。这将允许我们释放不是的图像   由您的申请保留。

     

我理解当前的解码行为并不明显   Silverlight保留了这些引用,但更改了解码器   设计可能影响其他领域,所以现在我建议处理   这样的图像分批。

     

现在,如果你真的试图加载500张图片并保留它们,那么你   根据图像大小,仍有可能内存不足。如果   您正在处理多页文档,您可能希望改为使用   在后台按需加载页面并在外出时释放它们   用几页缓冲区查看,这样你就不会超过   合理的纹理记忆限制。

<强>修正:

private List<BitmapImage> Images = .....;
private List<BitmapImage>.Enumerator iterator;
private List<byte[]> bytesData = new List<byte[]>();

public void ProcessImages()
{
    if(iterator == null)
        iterator = Images.GetEnumerator();

    if(iterator.MoveNext())
    {
        bytesData.Add(ConvertToBytes(iterator.Current));

        //load next images
        Dispatcher.BeginInvoke(() => ProcessImages());
    }else{
        //all images done
    }
}

public static byte[] ConvertToBytes(BitmapImage bitmapImage)
{
    using (MemoryStream stream = new MemoryStream())
    {
        var wBitmap = new WriteableBitmap(bitmapImage);
        wBitmap.SaveJpeg(stream, wBitmap.PixelWidth, wBitmap.PixelHeight, 0, 100);
        stream.Seek(0, SeekOrigin.Begin);
        return stream.ToArray();
    }
}

答案 2 :(得分:0)

我找到了将Bitmap Image转换为byte []数组的新方法。无需在内存中写入图像。 野兔是代码

 public byte[] GetBytes(BitmapImage bi)
    {
        WriteableBitmap wbm = new WriteableBitmap(bi);
        return ToByteArray(wbm);
    }
    public byte[] ToByteArray(WriteableBitmap bmp)
    {
        // Init buffer
        int w = bmp.PixelWidth;
        int h = bmp.PixelHeight;
        int[] p = bmp.Pixels;
        int len = p.Length;
        byte[] result = new byte[4 * w * h];

        // Copy pixels to buffer
        for (int i = 0, j = 0; i < len; i++, j += 4)
        {
            int color = p[i];
            result[j + 0] = (byte)(color >> 24); // A
            result[j + 1] = (byte)(color >> 16); // R
            result[j + 2] = (byte)(color >> 8);  // G
            result[j + 3] = (byte)(color);       // B
        }

        return result;
    }