none
wpf远程下载多张图片时,内存不断增大,求教怎么解决 RRS feed

  • 问题

  • private void button1_Click(object sender, RoutedEventArgs e)
            {
               
                for (int i = 0; i < 40; i++)
                {
                    WebClient webClient = new WebClient();
                    webClient.Credentials = new NetworkCredential("ftpuser", "ftppassword");
                    webClient.DownloadDataCompleted += (s, de) =>
                    {
                        MemoryStream ms2 = new MemoryStream(de.Result, 0, de.Result.Length);
                        ms2.Seek(0, SeekOrigin.Begin);
                        BitmapImage image = new BitmapImage();
                        image.BeginInit();
                        image.CacheOption = BitmapCacheOption.None;
                        image.CreateOptions = BitmapCreateOptions.None;
                        image.StreamSource = ms2;
                        image.EndInit();
                    };
                    webClient.DownloadDataAsync(new Uri(@"ftp://127.0.0.1/1/20090308/V_2/142/00000002.TIF"));
                }
            }这段代码是模拟的,连续点击几次按钮时,内存会不断增大,到最后会没内存了

           [DllImport("kernel32.dll")]
            public static extern bool SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
            public void FlushMemory()
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
            }这段代码也没用

    2012年3月5日 16:16

答案

  •       for (int i = 1; i <= 256; i++)
          {
            using (WebClient webClient = new WebClient())
            {
              //webClient.Credentials = new NetworkCredential("ftpuser", "ftppassword");
              webClient.DownloadDataCompleted += (s, de) =>
              {
                using (MemoryStream ms2 = new MemoryStream(de.Result, 0, de.Result.Length))
                {
                  ms2.Seek(0, SeekOrigin.Begin);
                  BitmapImage image = new BitmapImage();
                  //image.Freeze();
                  image.BeginInit();
                  //image.Freeze();
                  image.CacheOption = BitmapCacheOption.OnLoad;
                  image.CreateOptions = BitmapCreateOptions.None;
                  image.StreamSource = ms2;
                  image.EndInit();
    
                  image.Freeze();
    
                  //image1为image控件
    
                  image1.Source = image;
    
                }
              };
              webClient.DownloadDataAsync(new Uri(@"..."));
            }
          }
          GC.Collect();
          GC.WaitForPendingFinalizers();
          GC.Collect();
     
        }

    这样应该就可以了,我循环256次去拉数据,最高到1.4GB内存量,最后释放到100M左右。不过释放并不及时,基本上等了1分钟才全部放完,主要是大对象过多。

    然后如果我们开一个计时器每隔一段时间GC一下,效果会更好:

          InitializeComponent();
          DispatcherTimer timer = new DispatcherTimer();
          timer.Interval =new TimeSpan( 2000);
          timer.Tick += (o, e) =>
          {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
          };
          timer.Start();

    Sincerely,

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us


    2012年3月7日 3:24
    版主
  • ???

    2012年3月8日 4:12

全部回复

  • private void button1_Click(object sender, RoutedEventArgs e)
            {
               
                for (int i = 0; i < 40; i++)
                {
                    WebClient webClient = new WebClient();
                    webClient.Credentials = new NetworkCredential("ftpuser", "ftppassword");
                    webClient.DownloadDataCompleted += (s, de) =>
                    {
                        MemoryStream ms2 = new MemoryStream(de.Result, 0, de.Result.Length);
                        ms2.Seek(0, SeekOrigin.Begin);
                        BitmapImage image = new BitmapImage();
                        image.BeginInit();
                        image.CacheOption = BitmapCacheOption.None;
                        image.CreateOptions = BitmapCreateOptions.None;
                        image.StreamSource = ms2;
                        image.EndInit();
                    };
                    webClient.DownloadDataAsync(new Uri(@"ftp://127.0.0.1/1/20090308/V_2/142/00000002.TIF"));
                }
            }这段代码是模拟的,连续点击几次按钮时,内存会不断增大,到最后会没内存了

           [DllImport("kernel32.dll")]
            public static extern bool SetProcessWorkingSetSize(IntPtr process, int minSize, int maxSize);
            public void FlushMemory()
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
                if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                {
                    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
                }
            }这段代码也没用

    2012年3月5日 16:13
  • 尝试在 image.BeginInit(); 前 image.e(); 

    然后根据这篇文章 http://blogs.msdn.com/b/jgoldb/archive/2008/02/04/finding-memory-leaks-in-wpf-based-applications.aspx 最好能够先调试一下看看是什么对象没有被释放 (by Windbg)


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年3月5日 19:48
    版主
  • 谢谢您的关注,

    尝试在 image.BeginInit(); 前 image.e(); 

    image.e()???   这什么?

    文章经过翻译勉强看了一点。它说远程下载图片最好第一次保存到本地,然后下次调用本地的,就不会出现内存泄露,可是我的需求每次都是查看不同的图片啊

     for (int i = 0; i < 40; i++)
                {
                    WebClient webClient = new WebClient();
                    webClient.Credentials = new NetworkCredential("ftpuser", "ftppassword");
                    webClient.DownloadDataCompleted += (s, de) =>
                    {
                        MemoryStream ms2 = new MemoryStream(de.Result, 0, de.Result.Length);
                        ms2.Seek(0, SeekOrigin.Begin);
                        BitmapImage image = new BitmapImage();
                        image.BeginInit();
                        image.CacheOption = BitmapCacheOption.None;
                        image.CreateOptions = BitmapCreateOptions.None;
                        image.StreamSource = ms2;
                        image.EndInit();
                    };
                    webClient.DownloadDataAsync(new Uri(@"ftp://127.0.0.1/1/20090308/V_2/142/00000002.TIF"));
                }

    就这段代码,您能否帮我看下有什么问题?

    2012年3月6日 3:11
  • 不好意思,这个论坛编辑器回车容易错位,不小心删掉了点字母, 应该是:image.Freeze();

    然后你要注意关闭你的MemoryStream, 建议用using关键词去包裹你的MemoryStream对象。


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年3月6日 5:23
    版主
  • 非常感谢您的关注,谢谢!

    在 image.BeginInit();前用image.Freeze(); 提示图片不可修改。

    在异步里用using( MemoryStream ,图片不能正常显示了。

    for (int i = 0; i < 10; i++)
                {
                    WebClient webClient = new WebClient();
                    webClient.Credentials = new NetworkCredential("ftpuser", "ftppassword");
                    webClient.DownloadDataCompleted += (s, de) =>
                    {
                        using ( MemoryStream ms2 = new MemoryStream(de.Result, 0, de.Result.Length))
                        {
                            ms2.Seek(0, SeekOrigin.Begin);
                            BitmapImage image = new BitmapImage();
                            //image.Freeze();
                            image.BeginInit();
                            //image.Freeze();
                            image.CacheOption = BitmapCacheOption.None;
                            image.CreateOptions = BitmapCreateOptions.None;
                            image.StreamSource = ms2;
                            image.EndInit();

                            image.Freeze();

                            //image1为image控件

                            image1.Source = image;

                        }                 
                       
                    };
                    webClient.DownloadDataAsync(new Uri(@"ftp://127.0.0.1/1/20090308/V_2/142/00000002.TIF"));
                }

    有没有既能异步下载多张图片,又能及时释放内存的好方法啊~!~

    2012年3月6日 6:26
  •       for (int i = 1; i <= 256; i++)
          {
            using (WebClient webClient = new WebClient())
            {
              //webClient.Credentials = new NetworkCredential("ftpuser", "ftppassword");
              webClient.DownloadDataCompleted += (s, de) =>
              {
                using (MemoryStream ms2 = new MemoryStream(de.Result, 0, de.Result.Length))
                {
                  ms2.Seek(0, SeekOrigin.Begin);
                  BitmapImage image = new BitmapImage();
                  //image.Freeze();
                  image.BeginInit();
                  //image.Freeze();
                  image.CacheOption = BitmapCacheOption.OnLoad;
                  image.CreateOptions = BitmapCreateOptions.None;
                  image.StreamSource = ms2;
                  image.EndInit();
    
                  image.Freeze();
    
                  //image1为image控件
    
                  image1.Source = image;
    
                }
              };
              webClient.DownloadDataAsync(new Uri(@"..."));
            }
          }
          GC.Collect();
          GC.WaitForPendingFinalizers();
          GC.Collect();
     
        }

    这样应该就可以了,我循环256次去拉数据,最高到1.4GB内存量,最后释放到100M左右。不过释放并不及时,基本上等了1分钟才全部放完,主要是大对象过多。

    然后如果我们开一个计时器每隔一段时间GC一下,效果会更好:

          InitializeComponent();
          DispatcherTimer timer = new DispatcherTimer();
          timer.Interval =new TimeSpan( 2000);
          timer.Tick += (o, e) =>
          {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
          };
          timer.Start();

    Sincerely,

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us


    2012年3月7日 3:24
    版主
  •  因为你的图片并不大,而且数量较少,我用的很大的图测试的,且用了256张。所以效果明显。你加个计时器隔一段时间(可是几十秒,频率不用太高)GC下 然后 用Using 包 MemoryStream 和WebClient , Freeze Image 后,内存不会随时间增加很多,应该是一直维持一个稳定态。

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us


    2012年3月7日 16:30
    版主
  • ???

    2012年3月8日 4:12
  • 因为不用webclient页面会卡住不动啊,直到所有图片下载完毕才能跳转。。

    2012年3月29日 6:28
  • 晕。。。你是不是打了什么补丁啊,可以告诉我你的系统和软件运行环境么?

    2012年3月29日 7:39
  • Win 7 .Net 4.0  VS 2010环境

    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    2012年3月29日 8:27
    版主