I encountered a reported memory leak in my Android app, after some investigation I pretty much find out where the leak is, here is the simplified code:
public class LeakTracker {
public static List<Callback> callbacks = new ArrayList<>();
public static List<WeakReference<LeakingActivity>> weakList = new ArrayList<>();
// causes leak of activity
public void startLeak(final LeakingActivity activity) {
callbacks.add(new Callback() {
// remove this line then no leak
Wrapper wrapper = new Wrapper(activity);
@Override
public void onCall() {
}
});
}
// no leak here
public void startLeak2(final LeakingActivity activity) {
weakList.add(new WeakReference<>(activity));
}
public interface Callback {
void onCall();
}
static class Wrapper {
private WeakReference<LeakingActivity> weakReference;
public Wrapper(final LeakingActivity activity) {
weakReference = new WeakReference<LeakingActivity>(activity);
}
}
}
The leak happens because I call a function "startLeak". The activity variable will be leaked. However if I call "startLeak2" the leak won't happen. I am wondering why there is a leak in the first case. The Wrapper uses a WeakReference as well.
The LeakActivity class takes about 30M of memory. Calling startLeak about 5 times on an Android device causes OOM. Calling startLeak2 won't. And LeakCanary tool reports leak if using startLeak not startLeak2.