W polowaniu na wyciek pamięci w mojej aplikacji ścigałem zachowanie, którego nie mogę zrozumieć. Przydzielam duży blok pamięci, ale nie zbiera się w nim śmieci, czego skutkiem jest OOM, chyba że podaję zerowy odnośnik w onDestroy.Duża porcja pamięci nie śmieci zebrane
W tym przykładzie mam dwie prawie identyczne czynności, które przełączają się między sobą. Oba mają jeden przycisk. Po naciśnięciu przycisku MainActivity uruchamia OOMActivity i OOMActivity zwraca przez wywołanie finish(). Po kilkukrotnym naciśnięciu przycisków, Android rzuca OOMException.
Jeśli dodaję onDestroy do OOMActivity i explicite null odniesienie do porcji pamięci, widzę w dzienniku, że pamięć została poprawnie zwolniona.
Dlaczego pamięć nie jest automatycznie zwalniana bez zerowania?
główną działalność:
package com.example.oom;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
private int buttonId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.gc();
Button OOMButton = new Button(this);
OOMButton.setText("OOM");
buttonId = OOMButton.getId();
setContentView(OOMButton);
OOMButton.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == buttonId) {
Intent leakIntent = new Intent(this, OOMActivity.class);
startActivity(leakIntent);
}
}
}
OOMActivity:
public class OOMActivity extends Activity implements OnClickListener {
private static final int WASTE_SIZE = 20000000;
private byte[] waste;
private int buttonId;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button BackButton = new Button(this);
BackButton.setText("Back");
buttonId = BackButton.getId();
setContentView(BackButton);
BackButton.setOnClickListener(this);
waste = new byte[WASTE_SIZE];
}
public void onClick(View view) {
if (view.getId() == buttonId) {
finish();
}
}
}
świetny przykład, świetne pytanie! – WarrenFaith
Proszę przeczytać ten czat. Omówiliśmy to tutaj (http://chat.stackoverflow.com/transcript/message/10084186#10084186) – Reno
Prawdopodobnie testujesz to na urządzeniu o strukturze plastra miodu. Śmieciarka na post-plasterku będzie wystarczająco agresywna, aby uwolnić obiekt "odpadowy". Testowane w 4.1.2, 4.2.2, 2.3.5, 2.3.7. Wywołanie System.gc() przed "waste = new byte [WASTE_SIZE]" pozwala uniknąć problemu na urządzeniach o strukturze plastra miodu. – pellucide