C# WriteableBitmap上发生OutOfMemoryException

C# WriteableBitmap上发生OutOfMemoryException,c#,windows-phone-7,windows-phone-8,bitmapimage,C#,Windows Phone 7,Windows Phone 8,Bitmapimage,我正在开发一个windows phone应用程序,用于将图像上载到web服务器。我正在将设备中的所有图像选择到一个列表对象中。我正在将所有位图图像逐个转换为字节[] 我的代码 public byte[] ConvertToBytes(BitmapImage bitmapImage) { byte[] data = null; WriteableBitmap wBitmap = null; using (MemoryStream strea

我正在开发一个windows phone应用程序,用于将图像上载到web服务器。我正在将设备中的所有图像选择到一个列表对象中。我正在将所有位图图像逐个转换为字节[]

我的代码

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;
            }
          }
使用(IsolatedStorageFile store=IsolatedStorageFile.GetUserStoreForApplication())
{
如果(!store.DirectoryExists(“ImagesZipFolder”))
{
//MediaImage MediaImage=新的MediaImage();
//mediaImage.ImageFile=decodeImage(新字节[imgStream[0].Length]);
//lstmages.Items.Add(mediaImage);
store.CreateDirectory(“ImagesZipFolder”);
for(int i=0;i
我的模拟器中有91个图像。当我将所有这些位图图像转换为字节[]时,get在第
wBitmap=new WriteableBitmap(位图图像)行出现以下错误

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

如何解决此错误

网络服务

 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;
            }
          }
若我们将巨大的文件发送到web服务,它是否会给出类似这样的错误

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

如何解决此错误

改变你做事的方式,使用更少的内存

例如,不是转换每张图片然后上传它们,而是转换一张图片,上传它,转换下一张,依此类推

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

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


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

问题在于GC和位图图像如何协同工作,如本错误报告所述:

从报告中可以看出:

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();
    }
}
私有列表图像=。。。。。;
私有列表。枚举器迭代器;
私有列表bytesData=新列表();
public void ProcessImages()
{
if(迭代器==null)
迭代器=Images.GetEnumerator();
if(iterator.MoveNext())
{
Add(ConvertToBytes(iterator.Current));
//加载下一个图像
Dispatcher.BeginInvoke(()=>ProcessImages());
}否则{
//所有图像完成
}
}
公共静态字节[]转换字节(位图图像位图图像)
{
使用(MemoryStream stream=new MemoryStream())
{
var wBitmap=新的可写bitmap(位图图像);
SaveJpeg(stream,wBitmap.PixelWidth,wBitmap.PixelHeight,0100);
stream.Seek(0,SeekOrigin.Begin);
返回流ToArray();
}
}

我找到了将位图图像转换为字节[]数组的新方法。不需要在内存中写入图像。 兔子是密码

 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;
    }
public byte[]GetBytes(BitmapImage bi)
{
WriteableBitmap wbm=新的WriteableBitmap(bi);
返回到字节数组(wbm);
}
公共字节[]ToByteArray(WriteableBitmap bmp)
{
//初始化缓冲区
int w=bmp.PixelWidth;
int h=bmp.PixelHeight;
int[]p=bmp.像素;
int len=p.长度;
字节[]结果=新字节[4*w*h];
//将像素复制到缓冲区
对于(int i=0,j=0;i>24);//A
结果[j+1]=(字节)(颜色>>16);//R
结果[j+2]=(字节)(颜色>>8);//G
结果[j+3]=(字节)(颜色);//B
}
返回结果;
}

是否需要同时在内存中存储所有字节数组?