У службы фоновой передачи WP есть утечка памяти?
Недавно я обнаружил, что у службы фоновой передачи Windows Phone есть проблема с утечкой памяти.
Каждая добавленная вами фоновая передача займет место в памяти, которое не может быть удалено GC навсегда.
Я уже прочитал http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202959(v=vs.105).aspx, и до сих пор не знаю, откуда происходит утечка памяти.
То, что я тестирую, очень просто: добавьте запрос фоновой передачи в Background Transfer Service, а когда этот запрос будет выполнен, удалите его из Background Transfer Service и добавьте еще один. Если я продолжу это делать, я увижу, что память растет, даже когда вызывается 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(), я получаю каждый раз один и тот же хэш-код, и хэш-код даже совпадает с один я обновил и добавил в Background Transfer Service. Так это потому, что MS переопределяет метод GetHashCode в BackgroundTransferRequest? или я что-то неправильно понимаю. Но в приведенном выше примере кода я не использовал BackgroundTransferService.Requests для получения какого-либо экземпляра, память все еще продолжает расти.
Пожалуйста, скажите мне, что я делаю не так или любой обходной путь, спасибо...