如何创建全局可用的WebClient对象

时间:2015-05-20 19:15:09

标签: c# memory-leaks

我在Windows窗体中有一个下载程序,它下载了一堆URL的html源代码,并提取了更多的URL并下载了这些东西。我正在使用

using(WebClient client = new WebClient())
{
    // Do download stuff here...
}

但.NET Mem Profiler显示严重的内存泄漏,因为很多对象都是垃圾收集但未处理或处置但未收集垃圾。听起来很奇怪,但我的程序有内存泄漏。

要了解我的计划,请考虑以下代码:

private void PreprocessURLs(List<string> URLs)
{
    using(WebClient client = new WebClient())
    {
       // Download first batch of html source code and put in a List<string> property
    }
}

private void ProcessURLs(List<string> URLs)
{
    using(WebClient client = new WebClient())
    {
       // Download more stuff and save them
    }
}

等等。这不是实际的程序,但我想告诉你的是,如何创建一个“全局”可用的WebClient对象/实例,这样我就不会创建一堆客户端对象?我想重用它。我怀疑这是导致内存泄漏的原因(可能是其中之一)。也许我错了,因为我从来没有创建过一个可能会导致内存泄漏的程序。

编辑:在建议使用tlemster之后,我创建了一个WebClient的静态实例但由于不支持并发I / O而导致I / O错误(DownloadFileAsync())。

EDIT1:这是我的下载方法,它通过这样做来完成主要工作并阻止我的UI线程。因此我相信mem泄漏来自这个功能。

private void Download()
{
    var stopwatch = new Stopwatch();
    string bla;
    string chapterName;
    string bla1;
    string chapterNumber;
    List<Tuple<string, int>> temp = new List<Tuple<string, int>>();

    // Contains all URLs from preprocessing
    foreach (var chapter in Chapters)
    {
        bla = chapter.Item2;
        chapterName = ReplaceSpecialChars(bla);

        bla1 = chapter.Item3;
        chapterNumber = ReplaceSpecialChars(bla1);

        // Skip this chapter if it already exists based on chapter name
        if (Directory.Exists(string.Format("{0}/{1} - {2}", chapter.Item4, chapterNumber, chapterName)))
        {
            continue;
        }
        else
        {
            Directory.CreateDirectory(string.Format("{0}/{1} - {2}", chapter.Item4, chapterNumber, chapterName));
        }

        // Process each chapter and extract other URLs
        foreach (var item in GetPagesLink(chapter.Item1))
        {
            // Add the extracted URLs to a list for download further down
            temp.Add(new Tuple<string, int>(GetImageLink(item.Item1), item.Item2));
        }

        stopwatch.Start();

        // The download of the files I want after processing it two times
        foreach (var img in temp)
        {
            // A static WebClient does not work because DownloadFileAsync() does not support concurrent I/O
            // Atm should not matter because this whole thing is not async anyway...
            using (WebClient webClient = new WebClient())
            {
                webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
                webClient.DownloadFileAsync(new Uri(img.Item1), string.Format("{0}/{1} - {2}/{3}.jpg", chapter.Item4, chapterNumber, chapterName, img.Item2)); // TODO: Find image type and replace hardcoded jpg
                System.Threading.Thread.Sleep(150);
            }
        }
        stopwatch.Stop();
        temp.Clear();
        txtDebug.AppendText("Finished chapter " + chapter.Item3 + " : " + stopwatch.ElapsedMilliseconds + "\r\n");
        stopwatch.Reset();
    }
    Chapters.Clear();
}

1 个答案:

答案 0 :(得分:-1)

将创建的WebClient存储在一个静态字段中,只要程序正在运行或者直到你手动删除它,它就会使实例保持活动状态。