coil icon indicating copy to clipboard operation
coil copied to clipboard

Performance issue in lazy grid

Open PauliusVal opened this issue 2 years ago • 24 comments

Description Compose performance issue in super simple app which just displays network images list using Coil.

We see noticeable jank while scrolling even though:

  • app runs in R8 release mode
  • contains baseline profile for scrolling screen
  • stable Compose parameters used
  • unique and stable item keys applied for grid items

Jank is visible by human eye and also in profiler: https://github.com/PauliusVal/ComposeGridPerformance/blob/main/images/images_grid_janky_frames_1.png?raw=true

Full app code and more screenshots: https://github.com/PauliusVal/ComposeGridPerformance/tree/main

Version Coil version: io.coil-kt:coil-compose:2.4.0

PauliusVal avatar Sep 19 '23 09:09 PauliusVal

Thanks for the repro project. Which device did you run the tests on?

colinrtwhite avatar Sep 19 '23 15:09 colinrtwhite

Samsung S21 Ultra, Android 13

PauliusVal avatar Sep 19 '23 19:09 PauliusVal

Not sure if that helps, but updated the app with identical grid just with Glide image loading. It has noticeably fewer janky frames in profiler and looks/feels much smoother.

PauliusVal avatar Sep 20 '23 07:09 PauliusVal

Same problem here, seems to use a lot of memory! Up to 2gigs of memory in my app when scrolling in lazy column with images.

Mkohm avatar Sep 22 '23 09:09 Mkohm

Same issue janky frames with grid

lkhore avatar Nov 06 '23 13:11 lkhore

@Mkohm That sounds like it could be a separate memory leak. Please file an issue (ideally with a way to reproduce)!

@lkhore Did you test in release mode? Compose is often much slower in debug mode.

colinrtwhite avatar Nov 13 '23 18:11 colinrtwhite

Same problem in release and debug mode.

serhatkarakoca avatar Nov 28 '23 19:11 serhatkarakoca

Is there any progress on this issue

Kuki93 avatar Dec 15 '23 02:12 Kuki93

I've added benchmark and tracing here to make diagnosing this easier: https://github.com/matejdro/ComposeGridPerformance/commit/beb902c3ad6d1348c169fc4565524fcaf0da5c5

Here is an example trace file (from Pixel 7 Pro): ScrollBenchmark_scrollImageList_iter003_2023-12-21-08-27-41.perfetto-trace.zip

Not sure why the trace is so weird (it shows one big compose event spanning multiple seconds), but you can still drill down and it appears that rememberAsyncPainter is taking considerable time:

image

matejdro avatar Dec 21 '23 08:12 matejdro

Im noticing a heavy jank in scrolling with LazyGrid as well. In my application compose:lazylist:prefetch:measure is taking around 229.935506 ms 👀

hellosagar avatar Dec 24 '23 11:12 hellosagar

I am simple loading local images and showing with coil. There is a noticeable lagging (skipping lots of frames) especially in older devices. During first showing of the LazyVerticalGrid it is almost unusable. Below is the video to show the lag with HWUI rendering. And yes, it is in release mode. In debug you can't even scroll.

https://github.com/coil-kt/coil/assets/22423682/f3b42d97-6d29-438e-85c6-5cd009a028bd

musooff avatar Feb 06 '24 07:02 musooff

Same problem here with Coil's Compose Sample:

https://github.com/coil-kt/coil/assets/139561019/89527da3-7970-4f4a-83f3-50ddeefac54a

Coil version: 2.5.0 Device: Galaxy M23 5G

felipef0xx avatar Feb 07 '24 20:02 felipef0xx

It looks like it's not just related to LazyGrid. Changed the Compose Sample to LazyColumn and the problems still happen:

https://github.com/coil-kt/coil/assets/139561019/c2cda5bb-8e3e-4ebd-88cd-c5c7a12de1d9

felipef0xx avatar Feb 08 '24 16:02 felipef0xx

Hope I can somehow help with this. I am using LazyColumn and each item has an AsyncImage ("episode item"). Is there anything I can provide: debug logs, source code, ....?

mainrs avatar Feb 16 '24 16:02 mainrs

I have the same error, I'm using a LazyVerticalGrid with +8k items (I'm also using pagination), after fast scrolling through more than 3k items, the application gets super slow, even the android emulator stops working.

x3x0z avatar Apr 14 '24 13:04 x3x0z

Hope I can somehow help with this. I am using LazyColumn and each item has an AsyncImage ("episode item"). Is there anything I can provide: debug logs, source code, ....?

Does it still happen on 2.6.0?

Cj-Rodriguez101 avatar Apr 16 '24 21:04 Cj-Rodriguez101

@Cj-Rodriguez101 happens to me with a LazyVerticalGrid of AsyncImages on 2.6.0

mikelpr avatar Jun 13 '24 15:06 mikelpr

Facing same issue with 3.0.0-alpha06 on compose multiplatform.

starry-shivam avatar Jul 03 '24 16:07 starry-shivam

Facing same issue with 3.0.0-alpha06 on compose multiplatform.

I'd like to add that setting a fixed height to either AsyncImage via a modifier, or if it's wrapped in another composable like Box, then adding a fixed height to that parent composable, resolves the lag issue. The problem seems to be that it does not perform lazy loading of items when there is no fixed height set, causing all of them to load at once. I discovered this when I attached a DebugLogger() to the Coil configuration, and it printed 960+ items at once after the screen rendered, even though my grid is only large enough to show 6 items at a time. After adding a fixed height, the logger printed 8 items initially and continued printing more as I scrolled further, indicating that it was indeed performing lazy loading this time. As a result, there were no lags or jitters.

starry-shivam avatar Jul 04 '24 08:07 starry-shivam

Facing same issue with 3.0.0-alpha06 on compose multiplatform.

I'd like to add that setting a fixed height to either AsyncImage via a modifier, or if it's wrapped in another composable like Box, then adding a fixed height to that parent composable, resolves the lag issue. The problem seems to be that it does not perform lazy loading of items when there is no fixed height set, causing all of them to load at once. I discovered this when I attached a DebugLogger() to the Coil configuration, and it printed 960+ items at once after the screen rendered, even though my grid is only large enough to show 6 items at a time. After adding a fixed height, the logger printed 8 items initially and continued printing more as I scrolled further, indicating that it was indeed performing lazy loading this time. As a result, there were no lags or jitters.

Thank you for sharing! This did work in one of my apps. There are some UI experiences where this is not possible, though. For example in staggered grid views where items can have different heights depending on their content. That's where I encountered the issue.

mainrs avatar Jul 04 '24 09:07 mainrs

Thank you for sharing! This did work in one of my apps. There are some UI experiences where this is not possible, though. For example in staggered grid views where items can have different heights depending on their content. That's where I encountered the issue.

Yeah, this is just a workaround I found by trial and error. It cannot really cover all of the use cases. I really hope this bug gets fixed soon.

starry-shivam avatar Jul 04 '24 09:07 starry-shivam

Hey folks if you're having performance issues I'd recommend trying the latest 3.0.0 alphas, as it should be faster. There's been work done in AsyncImagePainter to avoid Compose and Coroutines overhead. Some of this work required changing the public API slightly, which is why it hasn't been backported to 2.x (though some slight improvements were backported to 2.7.0). Here's the upgrade guide.

Also I'd heavily recommend avoiding SubcomposeAsyncImage inside a list as it relies on subcomposition, which is slow. AsyncImage and rememberAsyncImagePainter are much faster.

colinrtwhite avatar Aug 01 '24 02:08 colinrtwhite

It got better after upgrading to 2.7.0, but still jittering. I've added a plain image (just for isolating coil) and I still got skipping frames on my 120hz pixel 7 pro. I suspect the Lazy Grid is becoming the issue from this point.

hypersebi avatar Aug 03 '24 11:08 hypersebi