Почему у меня перестает работать память после остановки загрузки? - PullRequest
3 голосов
/ 10 августа 2011

Моя программа загружает mp3-файлы размером от 5 до 100 МБ, а размер утечки памяти равен размеру загрузки. Использование памяти начинает постепенно увеличиваться после того, как я нажимаю кнопку, которая приостанавливает или отменяет загрузку. Эта дополнительная память обнуляется после того, как она заканчивает накапливать [размер файла] байтов памяти, но я не могу понять, что ее вызывает или как ее остановить.

Когда я пропускаю / отменяю загрузку, я изменяю состояние, которое он проверяет, чтобы он выходил из цикла загрузки и удалял поток из HttpWebResponse.GetResponseStream.

Затем использование памяти постепенно возрастает, например, при загрузке в 20 МБ она поднимется до 20 МБ (не имеет значения, если я приостановил ее в середине загрузки). Он поднимается со скоростью, необходимой для загрузки файла из Интернета. Когда он достигает этой суммы, он становится плато, если загрузка не была возобновлена ​​с паузы (если я отменил загрузку, она сразу же возвращается обратно после достижения этой точки). Когда я нажимаю «возобновить» загрузку, загрузка возобновляется, и как только она снова начинает получать данные, использование памяти немедленно падает до нормального уровня. Однако, в любом случае, он не избавится от утечки, пока не достигнет этой верхней точки.

Я пытался явно избавиться от всего, что связано, включая 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 Ответ

2 голосов
/ 13 августа 2011

Это помогло мне подумать об этом: 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 );

Внутри Download (), а не просто строка BeginGetResponse,

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

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

И в самом низу DownloadCallback (),

downloadBreakoutEvent.Set();

Я приостанавливаю / возобновляю его снова и снова, отменяю и перезапускаю снова и снова, что угодно, без утечек памяти!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...