Last active
December 21, 2017 23:43
-
-
Save nhachicha/4ba780712a7ae179cc67 to your computer and use it in GitHub Desktop.
Example demonstrating how to use PhantomReference to detect memory leak
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static class Activity { | |
interface Listener {} | |
Service service; | |
Activity(Service service) { | |
this.service = service; | |
} | |
void onStart() { | |
service.registerListener(new Listener() {});//Listener hold a reference to Activity | |
} | |
void onStop () { | |
service.unregisterListener(); | |
service = null; | |
} | |
} | |
static class Service { | |
Activity.Listener listener; | |
void registerListener (Activity.Listener listener) { | |
this.listener = listener; | |
} | |
void unregisterListener () { | |
this.listener = null; // comment this to cause a leak | |
} | |
} | |
// we want to make sure that Service will not leak the Activity | |
// because of the registered anonymous callback | |
public void test () throws InterruptedException { | |
Service service = new Service(); | |
Activity activity = new Activity(service); | |
activity.onStart(); | |
// store a PhantomReference to watch the lifecycle of listener | |
ReferenceQueue<Activity.Listener> referenceQueue = new ReferenceQueue<Activity.Listener>(); | |
PhantomReference<Activity.Listener> reference = | |
new PhantomReference<Activity.Listener>(service.listener, referenceQueue); // no need to store this reference since it's a root object (in stack memory) | |
activity.onStop(); | |
// reference = null; // uncomment to demonstrate why it's important to keep a strong reference to the PhantomReference | |
activity = null; // at this point we removed the strong reference to our Activity, | |
// service should not leak the Activity & Activity should be GC'd | |
// trigger the collection of PhantomReference | |
Runtime.getRuntime().gc(); | |
Reference<?> ref = referenceQueue.remove(TimeUnit.SECONDS.toMillis(10)); | |
assertNotNull(ref); | |
ref.clear(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment