WP后台传输服务有内存泄漏?

时间:2013-12-31 01:39:13

标签: c# windows-phone-7 memory-leaks garbage-collection background-transfer

最近,我发现Windows Phone后台传输服务似乎存在内存泄漏问题。

您添加的每个背景传输都会占用一个内存空间,GC无法永久删除。

我已经阅读了http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202959(v=vs.105).aspx,但仍然不知道内存泄漏的来源。

我测试的非常简单,向BackgroundTransferService添加后台传输请求,当该请求完成后,将其从BackgroundTransferService中删除并添加另一个。如果我继续这样做,即使每秒都调用GC.collect,我也会看到内存增长。请在http://hdtp.synology.me/BTS.zip下载测试代码,你就会知道我在说什么。以下是测试代码摘要。

    private int _transferCount = 1000;
private void CreateTask()
{
    if (--_transferCount < 0)
    {
        MessageBox.Show("End");
        return;
    }

    // Get the URI of the file to be transferred from the Tag property
    // of the button that was clicked.
    //string transferFileName = ((Button)sender).Tag as string;
    string transferFileName = "http://hdtp.synology.me/a.jpg";
    Uri transferUri = new Uri(Uri.EscapeUriString(transferFileName + "?ranNum=" + _transferCount), UriKind.RelativeOrAbsolute);

    // Create the new transfer request, passing in the URI of the file to 
    // be transferred.
    BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(transferUri);

    // Set the transfer method. GET and POST are supported.
    transferRequest.Method = "GET";

    // Get the file name from the end of the transfer Uri and create a local Uri 
    // in the "transfers" directory in isolated storage.
    string downloadFile = transferFileName.Substring(transferFileName.LastIndexOf("/") + 1);
    Uri downloadUri = new Uri("shared/transfers/" + downloadFile, UriKind.RelativeOrAbsolute);
    transferRequest.DownloadLocation = downloadUri;

    // Pass custom data with the Tag property. This value cannot be more than 4000 characters.
    // In this example, the friendly name for the file is passed. 
    transferRequest.Tag = downloadFile;

    // Add the transfer request using the BackgroundTransferService. Do this in 
    // a try block in case an exception is thrown.
    try
    {
        BackgroundTransferService.Add(transferRequest);
    }
    catch (InvalidOperationException ex)
    {
        // TBD - update when exceptions are finalized
        MessageBox.Show("Unable to add background transfer request. " + ex.Message);
    }
    catch (Exception)
    {
        MessageBox.Show("Unable to add background transfer request.");
    }

    InitialTansferStatusCheck();
}

private void InitialTansferStatusCheck()
{
    UpdateRequestsList();

    foreach (var transfer in transferRequests)
    {
        transfer.TransferStatusChanged += new EventHandler<BackgroundTransferEventArgs>(transfer_TransferStatusChanged);
        ProcessTransfer(transfer);
    }
}

private void transfer_TransferStatusChanged(object sender, BackgroundTransferEventArgs e)
{
    ProcessTransfer(e.Request);
}

private void UpdateRequestsList()
{
    // The Requests property returns new references, so make sure that
    // you dispose of the old references to avoid memory leaks.
    if (transferRequests != null)
    {
        foreach (var request in transferRequests)
        {
            request.Dispose();
        }
    }
    transferRequests = BackgroundTransferService.Requests;
}

private void ProcessTransfer(BackgroundTransferRequest transfer)
{
    switch (transfer.TransferStatus)
    {
        case TransferStatus.Completed:

            // If the status code of a completed transfer is 200 or 206, the
            // transfer was successful
            if (transfer.StatusCode == 200 || transfer.StatusCode == 206)
            {
                // Remove the transfer request in order to make room in the 
                // queue for more transfers. Transfers are not automatically
                // removed by the system.
                RemoveTransferRequest(transfer.RequestId);

                // In this example, the downloaded file is moved into the root
                // Isolated Storage directory
                using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    string filename = transfer.Tag;
                    if (isoStore.FileExists(filename))
                    {
                        isoStore.DeleteFile(filename);
                    }
                    isoStore.MoveFile(transfer.DownloadLocation.OriginalString, filename);
                }

                CreateTask();
            }
            else
            {
                // This is where you can handle whatever error is indicated by the
                // StatusCode and then remove the transfer from the queue. 
                RemoveTransferRequest(transfer.RequestId);

                if (transfer.TransferError != null)
                {
                    // Handle TransferError, if there is one.
                }
            }
            break;
    }
}

private void RemoveTransferRequest(string transferID)
{
    // Use Find to retrieve the transfer request with the specified ID.
    BackgroundTransferRequest transferToRemove = BackgroundTransferService.Find(transferID);

    // try to remove the transfer from the background transfer service.
    try
    {
        BackgroundTransferService.Remove(transferToRemove);
    }
    catch (Exception ex)
    {

    }
}

根据上面的文档,另外几个问题,我们每次都会从BackgroundTransferService.Requests获取新实例,但是如果我调用了GetHashCode(),我每次都会获得相同的哈希码,哈希码甚至是与我新建并添加到BackgroundTransferService中的那个相同。那么是因为MS覆盖了BackgroundTransferRequest的GetHashCode方法吗?或者我误解了一些事情。但是在上面的示例代码中,我没有使用BackgroundTransferService.Requests获取任何实例,内存仍在不断增长。

请告诉我我的错误或任何解决方法,谢谢......

0 个答案:

没有答案