saket / telephoto

Building blocks for designing media experiences in Compose UI
https://saket.github.io/telephoto/
Apache License 2.0
869 stars 28 forks source link

Possible resource leak #58

Closed MV-GH closed 5 months ago

MV-GH commented 6 months ago

I have enabled StrictMode with LeakedClosable detection. To search for resources leaks that are reported in the logs.

Possibly one is coming from this library.

StrictMode policy violation: android.os.strictmode.LeakedClosableViolation: A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
    at android.os.StrictMode$AndroidCloseGuardReporter.report(StrictMode.java:1924)
    at dalvik.system.CloseGuard.warnIfOpen(CloseGuard.java:303)
    at java.io.FileInputStream.finalize(FileInputStream.java:500)
    at java.lang.Daemons$FinalizerDaemon.doFinalize(Daemons.java:292)
    at java.lang.Daemons$FinalizerDaemon.runInternal(Daemons.java:279)
    at java.lang.Daemons$Daemon.run(Daemons.java:140)
    at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.Throwable: Explicit termination method 'close' not called
    at dalvik.system.CloseGuard.openWithCallSite(CloseGuard.java:259)
    at dalvik.system.CloseGuard.open(CloseGuard.java:230)
    at java.io.FileInputStream.<init>(FileInputStream.java:176)
    at okio.Okio__JvmOkioKt.source(JvmOkio.kt:181)
    at okio.Okio.source(Unknown Source:1)
    at okio.JvmSystemFileSystem.source(JvmSystemFileSystem.kt:96)
    at me.saket.telephoto.subsamplingimage.internal.ExifMetadata$Companion$read$2.invokeSuspend(ExifMetadata.kt:32)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

I get this pretty consistent on opening and closing a composable with ZoomableAsyncImage

Looked further into it. It passes a inputStream to ExifInterface that is not cleaned up.

  • Reads Exif tags from the specified image input stream. Attribute mutation is not supported
  • for input streams. The given input stream will proceed from its current position. Developers
  • should close the input stream after use. This constructor is not intended to be used with
  • an input stream that performs any networking operations.

This says consumers should close the resource and this is not done. It seems that a simple inputStream.close after exif should be sufficient. (at ExifMetadata$read)

saket commented 5 months ago

Thanks for reporting @MV-GH!