从隔离存储加载大量图像时出现OutOfMemory异常

时间:2012-04-13 01:06:49

标签: c# silverlight windows-phone-7

编辑:我一直没有得到OutOfMemoryException, 我认为这是我将图像保存到隔离存储的方式,我认为这是我可以解决问题的方法,如何在保存之前减小图像的大小? (添加了我保存图像的代码)

我正在从隔离存储中打开图像,有时超过100张图像,我想在它们上面循环图像,但是当有大约100到150张图像加载到故事板时,我得到OutOfMemory Exception。如何处理此异常,我已经降低了图像的分辨率。如何处理此异常并阻止我的应用程序崩溃?

我在这一行获得例外

image.SetSource(isStoreTwo.OpenFile(projectFolder + "\\MyImage" + i + ".jpg", FileMode.Open, FileAccess.Read));//images from isolated storage

这是我的代码

private void OnLoaded(object sender, RoutedEventArgs e)
    {


        IsolatedStorageFile isStoreTwo = IsolatedStorageFile.GetUserStoreForApplication();



        try
        {
            storyboard = new Storyboard
            {
                //RepeatBehavior = RepeatBehavior.Forever
            };

            var animation = new ObjectAnimationUsingKeyFrames();

            Storyboard.SetTarget(animation, projectImage);
            Storyboard.SetTargetProperty(animation, new PropertyPath("Source"));


            storyboard.Children.Add(animation);
            for (int i = 1; i <= savedCounter; i++)
            {
                BitmapImage image = new BitmapImage();

                image.SetSource(isStoreTwo.OpenFile(projectFolder + "\\MyImage" + i + ".jpg", FileMode.Open, FileAccess.Read));//images from isolated storage

                var keyframe = new DiscreteObjectKeyFrame
                {

                    KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(100 * i)),
                    Value = image
                };

                animation.KeyFrames.Add(keyframe);
            }
        }
        catch (OutOfMemoryException exc)
        {

            //throw;

        }



        Resources.Add("ProjectStoryBoard", storyboard);
        storyboard.Begin();
    }
  

编辑这就是我将图像保存到隔离存储的方式,我认为这是我可以解决问题的地方,如何在将图像保存到隔离存储时减小图像的大小?

    void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
    {

        string fileName = folderName+"\\MyImage" + savedCounter + ".jpg";

        try
        {  

            // Save picture to the library camera roll.
            //library.SavePictureToCameraRoll(fileName, e.ImageStream);



            // Set the position of the stream back to start
            e.ImageStream.Seek(0, SeekOrigin.Begin);

            // Save picture as JPEG to isolated storage.
            using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
            {
                using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
                {

                    // Initialize the buffer for 4KB disk pages.
                    byte[] readBuffer = new byte[4096];
                    int bytesRead = -1;

                    // Copy the image to isolated storage. 
                    while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
                    {
                        targetStream.Write(readBuffer, 0, bytesRead);
                    }

                }

            }




        }
        finally
        {
            // Close image stream
            e.ImageStream.Close();
        }

    }

如果你能帮助我,我将不胜感激。

7 个答案:

答案 0 :(得分:7)

您的图像在磁盘上的大小并不重要,因为当您将它们加载到内存中时,它们将会被解压缩。图像所需的内存大约为(stride * height)stridewidth * bitsPerPixel)/8,然后向上舍入为4个字节的下一个倍数。因此,每像素1024x768和24位的图像将占用大约2.25 MB。

您应该弄清楚图像的大小,未压缩,并使用该数字来确定内存要求。

答案 1 :(得分:5)

您正在获取OutOfMemory异常,因为您要同时将所有图像存储在内存中以创建StoryBoard。我认为您无法克服图像需要在屏幕上显示的未压缩位图大小。

因此,为了解决这个问题,我们必须考虑您的目标,而不是尝试修复错误。如果您的目标是每X ms按顺序显示一个新图像,那么您有几个选项。

  1. 继续使用StoryBoards,但使用OnCompleted事件将它们链接起来。这样您就不必一次创建它们,但只能生成接下来的几个。如果你每100毫秒更换一次图像,它可能不够快。

  2. 使用我answer here中提到的CompositionTarget.Rendering。如果您只是预加载下一个内存,则可能占用最少的内存(而不是像当前解决方案那样预先加载它们)。您需要手动检查已用时间。

  3. 重新思考你在做什么。如果你在人们可能有更多选择之后陈述你的意图。

答案 2 :(得分:1)

要回复帖子顶部的修改,请尝试ImageResizer。有一个NuGet包,还有一个HanselBlog集。显然,这是基于Asp.Net的,但我相信你可以在你的场景中使用它。

答案 3 :(得分:1)

在设计层处理这类问题通常效果更好。

通过某些配置使应用程序智能化运行环境,使您的应用程序更加强大。例如,您可以根据可用内存定义一些变量,如图像大小,图像数量,图像质量等,并在应用程序的运行时设置这些变量。所以你的应用程序总是有效在高内存机器上快速运行,在低内存机器上运行缓慢;但永远不会崩溃。 (不要相信在托管环境中工作意味着不要担心环境......设计总是很重要)

还有一些已知的设计模式,如Lazy Loading,您可以从中受益。

答案 4 :(得分:0)

好的,图片(1024x768)的memsize至少为3 mb(argb)

不知道ObjectAnimationUsingKeyFrames如何在内部工作。也许你可以通过破坏BitmapImage(和KeyFrames)的实例来强制gc,而不会丢失动画中的数据。 (不可能,请参阅评论!)

答案 5 :(得分:0)

我特别不了解Windows手机,但在.net winforms中,在执行长时间运行的任务时需要使用单独的线程。您使用的是BackgroundWorker还是等效的? finalizer thread can become blocked,它将阻止处理图像的资源。使用UI线程中的单独线程将允许Dispose方法自动运行。

答案 6 :(得分:0)

根据您的一条评论,您正在构建一个Time Lapse应用。 WP7的商业延时应用程序将图像压缩为视频,而不是静止图像。例如Time Lapse Pro

视频播放的重点是将类似或时间相关的图像缩小为高度压缩的流,不需要大量的内存来播放

如果您可以添加编码到视频的功能,在您的应用中,您将避免尝试模拟视频播放器的问题(使用100个单个全分辨率帧作为轻弹书)。

将图像处理成视频服务器端可能是另一种选择(但不像相机内那样友好)。