Android: AlertDialog verursacht einen Speicherverlust
Meine Anwendung zeigt ein AlertDialog
mit einem ListView
im inneren. Alles hat gut funktioniert bun dann habe ich beschlossen, dies zu testen für Speicher-Lecks. Nach dem ausführen der app für einige Zeit, die ich öffnete MATTE und generiert Leck Vermutet-Bericht. MAT fand mehrere ähnliche Lecks:
Einer Instanz von "com.android.intern.app.AlertController$RecycleListView" geladen "<system-class-loader>" nimmt ...
Verbrachte ich viel Zeit mit der Suche für den Grund der Undichtigkeit. Code-review hat mir nicht helfen und ich begann zu googeln. Das ist, was ich gefunden habe:
Habe ich beschlossen, um zu überprüfen, ob dieser bug reproduziert oder nicht. Für diesen Zweck erstellte ich ein kleines Programm, welches besteht aus zwei Aktivitäten. MainActivity
ist ein enrty Punkt. Es enthält nur die Schaltflächen, die läuft LeakedActivity
. Letztere zeigt nur eine AlertDialog
in seiner onCreate()
Methode. Hier ist der code:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startActivity(
new Intent(MainActivity.this, LeakedActivity.class));
}
});
}
}
public class LeakedActivity extends Activity {
private static final int DIALOG_LEAK = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
showDialog(DIALOG_LEAK);
}
}
@Override
protected Dialog onCreateDialog(int id) {
if (id == DIALOG_LEAK) {
return new AlertDialog.Builder(this)
.setTitle("Title")
.setItems(new CharSequence[] { "1", "2" },
new OnClickListener() {
private final byte[] junk = new byte[10*1024*1024];
@Override
public void onClick(DialogInterface dialog, int which) {
//nothing
}
})
.create();
}
return super.onCreateDialog(id);
}
}
MATTE Berichte dieser Anwendung Lecks com.android.internal.app.AlertController$RecycleListView
jedes mal, wenn die AlertDialog
abgewiesen und der LeakedActivity
fertig ist.
Ich finde keine Fehler in diesem kleinen Programm. Es sieht aus wie ein sehr einfacher Fall mit AlertDialog
und es muss gut funktionieren, doch scheint es nicht. Also ich würde gerne wissen, wie um Speicherverluste zu vermeiden, wenn mit AlertDialog
s mit Gegenständen. Und warum hat nicht dieses problem behoben wurde, noch? Vielen Dank im Voraus.
InformationsquelleAutor Michael | 2011-08-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
(2/12/2012): siehe UPDATE unten.
Dieses problem eigentlich nicht verursacht durch die
AlertDialog
aber mehr im Zusammenhang mit derListView
. Sie können reproduzieren das gleiche problem mit der folgenden Aktivität:Drehen Sie das Gerät mehrere Male, und Sie erhalten OOM.
Habe ich noch nicht die Zeit, zu untersuchen, mehr auf das, was die wirkliche Ursache (ich weiß was passiert aber nicht klar warum es passiert; bug, oder entwickelt). Aber hier ist eine Abhilfe, die Sie tun können, wenigstens um zu vermeiden, die OOM in Ihrem Fall.
Zunächst werden Sie benötigen, um einen Bezug zu Ihr durchgesickert
AlertDialog
. Sie können dies tun, in deronCreateDialog()
. Wenn Sie mitsetItems()
, dieAlertDialog
intern erstellen Sie eineListView
. Und wenn Sie dieonClickListener()
in IhremsetItems()
nennen, intern zugewiesen werden, dieListView
onItemClickListener()
.Dann, in die ausgetretene Aktivität
onDestroy()
, legen Sie dieAlertDialog
'sListView
'sonItemClickListener()
zunull
, die ist, wird Sie den Verweis auf die Zuhörer machen, was Speicher innerhalb dieser listener förderfähig zu sein für die GC. Auf diese Weise bekommen Sie dabei nicht OOM. Es ist nur ein Abhilfe und die wirkliche Lösung sollte eigentlich aufgenommen werden, in derListView
.Hier ist ein Beispiel-code für Ihre
onDestroy()
:UPDATE (2/12/2012): Nach einer weiteren Untersuchung, dieses problem ist eigentlich nicht besonders zu
ListView
nochOnItemClickListener
, sondern der Tatsache, dass GC nicht sofort geschehen und brauche Zeit, um zu entscheiden, welche Objekte in Frage kommen und bereit für die GC. Versuchen Sie dies:Drehen ein paar mal, und Sie erhalten die OOM. Das problem ist, nachdem Sie drehen, die
junk
noch beibehalten, weil GC noch nicht und kann es nicht noch passieren (wenn Sie mit MAT, werden Sie sehen, dass diesejunk
ist noch erhalten, indem Sie die Taste Hörer, tief unten aus der GCroot, und es wird Zeit für die GC, um zu entscheiden, ob diesejunk
ist förderfähig und kann GCed.) Aber zur gleichen Zeit, eine neuejunk
erstellt werden muss nach der Drehung, und da der mem alloc size (10M pro junk), dies wird verursachen OOM.Die Lösung ist, um zu brechen alle Verweise auf die Zuhörer (die
junk
Besitzer), in diesem Fall von der Taste, die praktisch macht die Zuhörer als GCroot mit nur kurzen Weg zu den Müll und machen die GC zu entscheiden, schneller zu reklamieren, die junk-Speicher. Diese kann getan werden, in deronDestroy()
:Toll. Würde der Geist Sie markieren Ihre Frage als beantwortet, so dass andere Menschen mit ähnlichem problem kann ganz einfach die Lösung.
Ja, natürlich. Mein Punkt ist, dass es viele Fragen mit guten Antworten bei stackoverflow aber nicht gekennzeichnet werden beantwortet (die Antwort wurde nicht akzeptiert). Es wird gut sein für die Gemeinschaft, wenn jeder, der bittet, ein bisschen verantwortlich-und mark/die Antwort akzeptieren, so dass es wird mehr hilfreich für andere mit ähnlichen problem.
Deine Antwort ist die beste, so das Kopfgeld gehört dir.
Hi , in meiner situation , es ist nicht über SetOnClickListiner , aber über Ansichten und Bild-Ressourcen, die in jedem ListViewItem , Wie kann ich dieses problem lösen ?
InformationsquelleAutor Ricky Lee
Nicht reproduzieren for Android
2.3.42.3.3. Getestet habe ich Ihre genauen code auf einem tatsächlichen Gerät und von dem, was ich sehe, in LogCat, die heap-Größe bleibt konstant über die Zeit. Leider war ich nicht in der Lage, hprof-conf meine dumps (FEHLER: erwartet 1.0.3)Ich habe es gerade getestet auf Google Nexus S mit Android 2.3.4 und es Lecks. Das ist ganz einfach zu gewährleisten, wenn das Leck vorhanden ist. Initialisieren
junk
mitnew byte[10*1204*1024]
führenLeakActivity
und drehen Sie ein Gerät mehrere Male. Die app stürzt mit OOM auf dem Nexus S nach der zweiten rotation.HTC Sensation w/ Revolution HD 1.1.8.
Ich überprüfte den code mit erhöhten junk-Größe (5 MB). Kein problem. Max-heap (in meinem Fall) wird berichtet, wie 32 MByes (ActivityManager.getMemoryClass()). Beachten Sie, dass GC in der Regel braucht einige Zeit, um Speicherplatz freizugeben. Was ich nicht weiß ist, ob der Speicher-block in einem chunk, also unfragmented.
Getan: 8 * 1024 * 1024. Verändert die Orientierung zu 30 mal ohne Probleme. Speicher ist schnell aufgearbeitet. Auch mit 2-oder 3-Puffer mit kumulierten Größe < 11 MB funktioniert einwandfrei. Sie könnten auch interessiert sein in der "Google I/O 2011: die Speicherverwaltung für Android-Apps" link
InformationsquelleAutor Horst Dehmer
Hatte ich ausführen von code und wenn ich das erste drücken der Taste zeigt die LeakedActivity mit dialog und onClick ist es das entfernen-dialog, aber die Aktivität bleibt im Vordergrund mit dem schwarzen Bildschirm. Beim betätigen der zurück-Taste und dann wieder ab die Aktivität zeigt den Arbeitsspeicher-Fehler, Ausnahme:
Dann ich entfernt die Zeile
private final byte[] junk = new byte[10*1024*1024];
aus dem dialog-code nach, dass dieses problem nicht existiert....weiß nicht, warum, wenn jemand diese Sache in Worte, vielen Dank an ihn/Sie..junk
Feld wurde Hinzugefügt, um zu füllen die Haufen schneller. Es muss GC ' ed, nach derLeakedActivity
ist fertig, aber es ist nicht. Und das ist der Punkt.InformationsquelleAutor Vineet Shukla
Müssen Sie Sie zu verwerfen/Abbrechen, um den dialog aus der onClick-Methode, siehe Beispiel hier : Alert-Dialoge in Android
InformationsquelleAutor Brandon Haugen