question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItΒ collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Coil leaks Activity Context when an Activity with an ongoing request is destroyed

See original GitHub issue

Describe the bug Coil causes a memory leak when finish() is called on an Activity that has an ongoing request.

To Reproduce Download & run the attached project: CoilMemoryLeak.zip

ActivityA tries to load an β€œimage” from a URL that takes 60 seconds to respond. If you click the β€œGo to Activity B” button during that time, then LeakCanary should detect retained objects (check the notification). This does not happen if the request has finished before going to ActivityB.

Expected behavior Any references to the Activity should always be cleared when it is destroyed.

Logs/Screenshots

2019-08-12 14:51:11.619 8859-9256/com.example.coilmemoryleak D/LeakCanary: HeapAnalysisSuccess(heapDumpFile=/data/user/0/com.example.coilmemoryleak/files/leakcanary/2019-08-12_14-50-53_530.hprof, createdAtTimeMillis=1565610671616, analysisDurationMillis=14783, applicationLeaks=[ApplicationLeak(className=com.example.coilmemoryleak.ActivityA, leakTrace=
    ┬
    β”œβ”€ android.os.HandlerThread
    β”‚    Leaking: NO (PathClassLoader↓ is not leaking)
    β”‚    Thread name: 'LeakCanary-Heap-Dump'
    β”‚    GC Root: Thread object
    β”‚    ↓ thread HandlerThread.contextClassLoader
    β”œβ”€ dalvik.system.PathClassLoader
    β”‚    Leaking: NO (Object[]↓ is not leaking and A ClassLoader is never leaking)
    β”‚    ↓ PathClassLoader.runtimeInternalObjects
    β”œβ”€ java.lang.Object[]
    β”‚    Leaking: NO (Coil↓ is not leaking)
    β”‚    ↓ array Object[].[870]
    β”œβ”€ coil.Coil
    β”‚    Leaking: NO (a class is never leaking)
    β”‚    ↓ static Coil.imageLoader
    β”‚                  ~~~~~~~~~~~
    β”œβ”€ coil.RealImageLoader
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ RealImageLoader.loaderScope
    β”‚                      ~~~~~~~~~~~
    β”œβ”€ kotlinx.coroutines.internal.ContextScope
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ ContextScope.coroutineContext
    β”‚                   ~~~~~~~~~~~~~~~~
    β”œβ”€ kotlin.coroutines.CombinedContext
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ CombinedContext.left
    β”‚                      ~~~~
    β”œβ”€ kotlinx.coroutines.SupervisorJobImpl
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ SupervisorJobImpl._state
    β”‚                        ~~~~~~
    β”œβ”€ kotlinx.coroutines.NodeList
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ NodeList._next
    β”‚               ~~~~~
    β”œβ”€ kotlinx.coroutines.ChildHandleNode
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ ChildHandleNode.childJob
    β”‚                      ~~~~~~~~
    β”œβ”€ kotlinx.coroutines.StandaloneCoroutine
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ StandaloneCoroutine._state
    β”‚                          ~~~~~~
    β”œβ”€ kotlinx.coroutines.ChildHandleNode
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ ChildHandleNode.childJob
    β”‚                      ~~~~~~~~
    β”œβ”€ kotlinx.coroutines.UndispatchedCoroutine
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ UndispatchedCoroutine.uCont
    β”‚                            ~~~~~
    β”œβ”€ coil.RealImageLoader$load$job$1
    β”‚    Leaking: UNKNOWN
    β”‚    Anonymous subclass of kotlin.coroutines.jvm.internal.SuspendLambda
    β”‚    ↓ RealImageLoader$load$job$1.$request
    β”‚                                 ~~~~~~~~
    β”œβ”€ coil.request.LoadRequest
    β”‚    Leaking: UNKNOWN
    β”‚    ↓ LoadRequest.context
    β”‚                  ~~~~~~~
    β•°β†’ com.example.coilmemoryleak.ActivityA
    ​     Leaking: YES (Activity#mDestroyed is true and ObjectWatcher was watching this)
    ​     key = 0893b148-6f03-4932-ad48-e07e204abb86
    ​     watchDurationMillis = 336257
    ​     retainedDurationMillis = 331257
    , retainedHeapByteSize=69591)], libraryLeaks=[])

Library version 0.6.0

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:3
  • Comments:12 (6 by maintainers)

github_iconTop GitHub Comments

6reactions
colinrtwhitecommented, Aug 13, 2019

Was able reproduce this with the sample application. I’ve verified that Coil is calling the OkHttp Call.cancel API as soon as the lifecycle is destroyed, however the Request object is being held onto longer than needed. Going to keep looking tomorrow.

5reactions
colinrtwhitecommented, Aug 20, 2019

For those following this ticket, I’ve been prioritizing other issues since the fix for this isn’t straightforward. Coil’s OkHttpClient is holding onto the request object slightly longer than the containing lifecycle, but it will ultimately be GC’d.

Going to circle back on this when some of the other issues have been fixed, but if anyone from the community has a clean way to fix this, feel free to submit a PR!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why using Activity context cause Context memory leak
If you use your activity as the context for something which is not tied to the life cycle of your activity and then...
Read more >
Application Context, Activity Context and Memory leaks
When activity is destroyed that context also be destroyed with it and it prevents memory leaks.
Read more >
International Standard Industrial Classification of All Economic ...
Its main purpose is to provide a set of activity categories that can be utilized for the collection and report- ing of statistics...
Read more >
Work Activities β€” Repairing and Maintaining Mechanical ...
Importance Level Job Zone Code 97 86 3 49‑9081.00 94 91 2 49‑9044.00 94 86 3 47‑4021.00
Read more >
The Mechanism of Double-Strand DNA Break Repair ... - NCBI
XRCC4:DNA ligase IV is able to stimulate DNA-PKcs kinase activity (96). The ligase complex also stimulates the pol mu and lambda activities in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found