I'm using MemoryAnalyzer tool to find memory leaks in my Android applicaton. So I run my application, visit all the activities, then press back until I get to the desktop. Then I use DDMS to get a memory dump (having pressed Cause GC several times).
Then I use an OQL query select * from instanceof android.app.Activity
to find leaking activities, and then press Merge Shortest Path to GC Roots -> exclude all phantom/weak/soft/etc references on a leaked object. And here I have this picture:
So it seems that somewhere in the system there is a static object BubblePopupHelper.sHelper
, which retains a reference to an EditText
view from my activity, causing the entire activity to leak! But what is this BubblePopupHelper
? I couldn't find any information on this class in the official docs. And how can I prevent my activity from being keeped in memory due to being referenced by this strange object?
I was testing on LG L40 device, running API19
Memory leaks occur when an application allocates memory for an object, but then fails to release the memory when the object is no longer being used. Over time, leaked memory accumulates and results in poor app performance and even crashes.
The Memory Profiler is a component in the Android Profiler that helps you identify memory leaks and memory churn that can lead to stutter, freezes, and even app crashes. It shows a realtime graph of your app's memory use and lets you capture a heap dump, force garbage collections, and track memory allocations.
My leak detection tools report the same leak on a regular basis, from LG phones only:
object com.squareup.SomeActivity
`-mContext of object android.widget.EditText
`-mView of object android.widget.BubblePopupHelper
`-sHelper of class android.widget.BubblePopupHelper
Manufacturers like to change the private APIs of the Android SDK under the hood. This is a memory leak introduced by LG.
From what I can gather, the focused EditText uses that BubblePopupHelper, probably to display some copy/paste popup or the text handle. Since there's only one focused edit text at a time, they made the helper a singleton, and it keeps a reference to the latest edit text focused.
So that means an entire Activity & its entire view hierarchy will leak, until another edit text gets focused.
How can you fix that? Sadly, this is SDK code, so while this might be fixed in future releases from LG, there will always be some users with that bug.
While this bug is certainly not your fault, it still is a memory leak, which can leak to increased OutOfMemory Errors. So, it's worth attempting to fix it,
There is a way, but it's not pretty. When the activity is destroyed, you can use reflection to clear the leak. For instance, one way could be to clear the sHelper field, or another one would be to clear the mView field on the helper. Either way, you should try that on the device (I don't have it right now) and see if it works.
private static final Executor backgroundExecutor =
newCachedThreadPool(backgroundThreadFactory("android-leaks"));
public static void fixLGBubblePopupHelper(final Application application) {
backgroundExecutor.execute(new Runnable() {
@Override public void run() {
final Field sHelperField;
try {
Class<?> bubbleClass = Class.forName("android.widget.BubblePopupHelper");
sHelperField = bubbleClass.getDeclaredField("sHelper");
sHelperField.setAccessible(true);
} catch (Exception ignored) {
// We have no guarantee that this class / field exists.
return;
}
application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksAdapter() {
@Override public void onActivityDestroyed(Activity activity) {
try {
sHelperField.set(null, null);
} catch (IllegalAccessException ignored) {
}
}
});
}
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With