In a hunt for a memory-leak in my app I chased down a behaviour I can't understand. I allocate a large memory block, but it doesn't get garbage-collected resulting in a OOM, unless I explicit null the reference in onDestroy.
In this example I have two almost identical activities that switch between each others. Both have a single button. On pressing the button MainActivity starts OOMActivity and OOMActivity returns by calling finish(). After pressing the buttons a few times, Android throws a OOMException.
If i add the the onDestroy to OOMActivity and explicit null the reference to the memory chunk, I can see in the log that the memory is correctly freed.
Why doesn't the memory get freed automatically without the nulling?
MainActivity:
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();
}
}
}