WP Background Transfer Service has Memory Leak?

526 Views Asked by At

Recently, I found that Windows Phone Background Transfer Service seems to have memory leak issue.

Every background transfer you add will take a memory space, which cannot be removed by GC forever.

I already read through http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202959(v=vs.105).aspx , and still have no idea where the memory leak comes from.

What I test is very simple, add a background transfer request to the BackgroundTransferService and when that request is complete, remove it from BackgroundTransferService and add another one. If I keep doing it, I'll see the memory grows even when GC.collect being called every sec. Please download the testing code in http://hdtp.synology.me/BTS.zip and you'll know what I'm saying. The following is the testing code summary.

    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)
    {

    }
}

Another few questions, according to the documentation above, we'll get the new instance from BackgroundTransferService.Requests every time, but if I called GetHashCode(), I get the same hash code every time and the hash code is even the same with the one I newed and added into BackgroundTransferService. So is it because MS override the GetHashCode method of BackgroundTransferRequest? or I misunderstand something. But in the sample code above, I did not use BackgroundTransferService.Requests to get any instance, the memory still keep growing.

Please tell me what I do wrong or any workaround, thanks...

0

There are 0 best solutions below