停止下载后,为什么我的内存使用会爆炸?

时间:2011-08-10 19:31:46

标签: c# windows-phone-7 memory-management httpwebrequest

我的程序下载的mp3文件大小从5MB到100MB不等,内存“泄漏”大小就是下载的大小。单击暂停或取消下载的按钮后,内存使用量开始逐渐增加。在完成累积[filesize]字节的内存后,额外​​的内存会自行消耗,但我无法弄清楚是什么导致它或如何阻止它。

当我跳过/取消下载时,我会更改它检查的状态,以便它退出下载循环并从HttpWebResponse.GetResponseStream处理流。

然后内存使用量逐渐增加,例如,对于20MB的下载量,它将增加20MB(如果我在下载过程中暂停一下,则无关紧要)。它大约从文件从互联网上下载所需的速度上升。当它达到那个数量时,如果下载还没有从暂停中恢复,那么它会在那里稳定下来(如果我取消了下载,它会在达到该点后立即恢复)。当我在下载时点击恢复时,下载会自动重启,一旦再次开始获取数据,内存使用率就会立即下降到正常状态。但是,无论哪种方式,它都不会在泄漏达到最高点之前消除泄漏。

我已尝试明确处理所涉及的所有内容,包括httpwebresponse,并且它没有改变任何内容。似乎某些东西没有被关闭,或者某些东西保留了流的引用,使其累积并将内容存储在内存中而被忽略了......?我不知道该去哪里,还有什么可以给我提供线索。我希望有一个资源监视器可以告诉我什么样的内容占用了所有的内存。任何帮助表示赞赏。

这是我正在使用的代码,尽管我可以保持它没有太多的混乱:

public void Download()
{
    while( paused )
    {
        Thread.Sleep( 1000 );
    }

    if( canceled )
        // signal end of download
    else
    {
        // Checking, rechecking, if/else/etc. In short, this:
        Enabled = true;
        var request = (HttpWebRequest)WebRequest.Create( url );
        request.AllowReadStreamBuffering = false;

        if( m_bytesCurrentlyDownloaded != 0 )
        {
            request.Headers["Range"] = string.Format( "bytes={0}-{1}",
                m_bytesCurrentlyDownloaded.ToString(),
                Filesize - 1 );
        }
        request.BeginGetResponse( new AsyncCallback( DownloadCallback ), request );
    }
}


private void DownloadCallback(IAsyncResult result)
{
    var request = (HttpWebRequest)result.AsyncState;

    HttpWebResponse response;
    try
    {
        response = (HttpWebResponse)request.EndGetResponse( result );
    }
    catch( WebException e )
    {
        response = (HttpWebResponse)e.Response;
    }

    if( response.StatusCode == HttpStatusCode.OK ||
        response.StatusCode == HttpStatusCode.PartialContent )
    {
        FileMode openMode = (m_bytesCurrentlyDownloaded == 0) ? FileMode.OpenOrCreate : FileMode.Append;

        using( var stream = response.GetResponseStream() )
        using( var appStorage = IsolatedStorageFile.GetUserStoreForApplication() )
        using( var file = new IsolatedStorageFileStream( m_incompleteFilename, openMode, FileAccess.Write, appStorage ) )
        {
            byte[] chunk = new byte[chunkSize];
            int readLength = 0;

            do
            {
                if( paused || canceled )
                    readLength = 0;
                else
                {
                    readLength = stream.Read( chunk, 0, chunkSize );

                    if( readLength != 0 )
                    {
                        file.Write( chunk, 0, readLength );
                        m_bytesCurrentlyDownloaded = (int)file.Length;
                    }
                }
            } while( readLength != 0 );

            chunk = null;
        }
        if( m_bytesCurrentlyDownloaded < Filesize ) // got paused, or connection drop
        {
            NeedWaitForNetwork(); // waits only if it needs to
            Download();
        }
        else
            FinishDownload();
    }
}

1 个答案:

答案 0 :(得分:2)

这有助于我思考:http://msdn.microsoft.com/en-us/magazine/cc163491.aspx听起来像堆栈泄漏给我。线程构成堆栈。总觉得我的控制之外的线程累积了所有内存,可能是某些属于HttpWebRequest / Response的线程。

这对我也很有帮助:http://www.geekpedia.com/tutorial179_Creating-a-download-manager-in-Csharp.html他正在做类似的事情,当他停止下载时,他会彻底中止他所做的下载线程。那个.Abort()调用响了,我调查了HttpWebRequest.Abort()。

昨天学习一下ManualResetEvent也有帮助。所以现在我的代码添加了这个:

在我的下载程序类中添加了一个成员:

private ManualResetEvent downloadBreakoutEvent = new ManualResetEvent( false );

Inside Download(),而不仅仅是BeginGetResponse行,

downloadBreakoutEvent.Reset();
request.BeginGetResponse( new AsyncCallback( DownloadCallback ), request );
downloadBreakoutEvent.WaitOne();

if( canceled || paused )
{
    request.Abort();
}

在DownloadCallback()的最底部,

downloadBreakoutEvent.Set();

我一遍又一遍地暂停/恢复它,一遍又一遍地取消和重启,无论如何,没有内存泄漏!