sto usando il codice qui sotto per creare un riquadro live, basato su un elemento dell'interfaccia utente. Restituisce il su un WriteableBitmap
, salva la bitmap + restituisce il nome file. Questo metodo viene eseguito in un task agent in background di Windows Phone e sto eseguendo dei limiti di memoria.WriteableBitmap Perdita di memoria?
private string CreateLiveTileImage(Canvas uiElement, int width, int heigth)
{
var wbmp = new WriteableBitmap(width, heigth);
try
{
wbmp.Render(uiElement, null);
wbmp.Invalidate();
var tileImageName = _liveTileStoreLocation;
using (var stream = new IsolatedStorageFileStream(tileImageName, FileMode.Create, FileAccess.Write, IsolatedStorageFile.GetUserStoreForApplication()))
{
wbmp.SaveJpeg(stream, width, heigth, 0, 100);
stream.Close();
}
uiElement = null;
wbmp = null;
GC.Collect();
return "isostore:" + tileImageName;
}
catch (Exception exception)
{
// ...
}
return null;
}
ho fatto alcuni test e il problema è: Questo metodo perdite di memoria, ma non so il motivo per cui /dove ?!
ho fatto anche alcune piste di prova - prima del primo eseguito in questo modo:
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
7.249.920 Bytes
Questo è ok, dal momento che il debugger è collegato, che utilizza circa 2 MB di memoria.
Facendo alcuni più esecuzioni di questo metodo (arretrato a correre di nuovo metodo di debugger):
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
8851456 long + 40960
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
8892416 long + 245760
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9138176 long + 143360
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9281536 long + 151552
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9433088 long + 143360
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9576448 long + 139264
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9715712 long + 139264
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
9859072 long + 143360
Microsoft.Phone.Info.DeviceStatus.ApplicationCurrentMemoryUsage
10006528 long + 147456
Così la memoria, utilizzata da questo metodo aumenta.
Ma perché? Secondo me non ci sono riferimenti che impediscono il recupero degli oggetti.
UPDATE 04.05.2013
Ciao,
grazie per tutte le vostre risposte! Come suggerito, ho ridotto il codice + finnally è stato in grado di riprodurre il problema in poche righe di codice.
void Main()
{
for (int i = 0; i < 100; i++)
{
CreateImage();
}
}
private void CreateImage()
{
var rectangle = CreateRectangle();
var writeableBitmap = new WriteableBitmap(rectangle, rectangle.RenderTransform);
rectangle = null;
writeableBitmap = null;
GC.Collect();
}
private Rectangle CreateRectangle()
{
var solidColorBrush = new SolidColorBrush(Colors.Blue);
var rectangle = new Rectangle
{
Width = 1000,
Height = 1000,
Fill = solidColorBrush // !!! THIS causes that the image writeableBitmap never gets garbage collected
};
return rectangle;
}
Dopo aver avviato App: ApplicationCurrentMemoryUsage: "11 681 792 Bytes"
1 Iterazione - ApplicationCurrentMemoryUsage: "28 090 368 Bytes"
5 iterazioni - ApplicationCurrentMemoryUsage: "77 111 296 Byte"
20 iterazioni - ApplicationCurrentMemoryUsage: "260 378 624 Bytes"
Dopo 23 iterazioni: Eccezione memoria esaurita. Ln .: var writeableBitmap = new WriteableBitmap (rettangolo, rettangolo.RenderTransform);
Solo commentando la riga "Fill = solidColorBrush", il metodo CreateImage() è stato chiamato 100 volte senza problemi - dopo la 100a iterazione, l'utilizzo della memoria era di circa "16 064 512 byte".
Quindi sembra che il problema sia il pennello !! Quando viene utilizzato per riempire un elemento dell'interfaccia utente e in seguito questo elemento di interfaccia utente viene visualizzato su una bitmap scrivibile, la bitmap non viene mai raccolta.
Ovviamente questo non ha senso secondo me. Il pennello esegue run-of-scope in modo che sia semplicemente necessario raccogliere dati inutili! (L'impostazione del pennello su null dopo l'utilizzo non ha modificato nulla)
Molti dei miei elementi dell'interfaccia utente utilizzano un pennello per il riempimento, quindi non posso semplicemente rimuovere l'utilizzo dei pennelli. Cosa ne pensi di questo problema?
Si noti che di solito non c'è alcun motivo per chiamare direttamente GC.Collect(). Può essere dannoso, bloccare la tua applicazione e ha un impatto sulle prestazioni. –
È vero, era più una sorta di "tentativo disperato", in realtà non fa nulla e non ha alcuna influenza sul consumo di memoria. – Hannes
Sei curioso di sapere cosa succede se finalizzi la tela? – Tebc