-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ListView leaks memory and doesn't clean up (Android) #12512
Comments
Summary: We really need a better list view - so here it is! Main changes from existing `ListView`: * Items are "virtualized" to limit memory - that is, items outside of the render window are unmounted and their memory is reclaimed. This means that instance state is not preserved when items scroll out of the render window. * No `DataSource` - just a simple `data` prop of shape `Array<any>`. By default, they are expected to be of the shape `{key: string}` but a custom `rowExtractor` function can be provided for different shapes, e.g. graphql data where you want to map `id` to `key`. Note the underlying `VirtualizedList` is much more flexible. * Fancy `scrollTo` functionality: `scrollToEnd`, `scrollToIndex`, and `scrollToItem` in addition to the normal `scrollToOffset`. * Built-in pull to refresh support - set set the `onRefresh` and `refreshing` props. * Rendering additional rows is usually done with low priority, after any interactions/animations complete, unless we're about to run out of rendered content. This should help apps feel more responsive. * Component props replace render functions, e.g. `ItemComponent: ReactClass<{item: Item, index: number}>` replaces `renderRow: (...) => React.Element<*>` * Supports dynamic items automatically by using `onLayout`, or `getItemLayout` can be provided for a perf boost and smoother `scrollToIndex` and scroll bar behavior. * Visibility callback replaced with more powerful viewability callback and works in vertical and horizontal mode on at least Android and iOS, but probably other platforms as well. Extra power comes from the `viewablePercentThreshold` that lets the client decide when an item should be considered viewable. Demo: https://www.facebook.com/groups/576288835853049/permalink/753923058089625/ Reviewed By: yungsters Differential Revision: D4412469 fbshipit-source-id: e2d891490bf76fe14df49294ecddf78a58adcf23
Same issue, except my app is actually in production and all my Android users are pissed giving me 1 star reviews, some in particular complaining about the memory usage. 😝 The more I scroll down the list, the slower the app becomes. List items include Image and TouchableOpacity, which like the OP said, makes it even worse. |
Hello! What you are describing here is (sadly) the intended behavior of react-native's |
Hey @brentvatne, @jasongrishkoff mentioned Anything else worth trying? |
@booboothefool - is there anything else in your app that would make it slower? like maybe each row is subscribing to redux events? I'd try profiling your app to see where the slowness is coming from |
Your memory usage low enough that the garbage collector might not even be kicking in, depending on the device you're running on. Try rendering more like 10000 rows and see if the memory continues to increase linearly or if it ever actually runs out of memory and crashes. |
As for slowness, I agree with @brentvatne that there is probably something else going on. |
Right, so I've got FlatList working using the very basic example provided in FlatListExample.js + ListExampleShared.js. No other modules or fancy things in my project -- it's a fresh install. The only thing I did was remove the thumbnails from the example. EXAMPLE 1 WITH VIRTUALIZED = TRUE AND fixedHeight = TRUE Okay from there, it tends to hover around 132MB -- which is too high and will get killed by Android as soon as I started to use other apps (I'm on a Nexus 5X, so not a bad phone). Sure enough, I opened Gmail, then WhatsApp, and my AwesomeProject was cleaned in the background. Also note that scrolling was a bit choppy. I'd move down the feed and it'd sorta take a while to gather its positioning. EXAMPLE 2 WITH VIRTUALIZED = TRUE AND fixedHeight = FALSE So, in both cases it stopped hemorrhaging memory around the ~137MB mark. But again, that's way too high. |
Does this look normal to you guys? (before and after scrolling an infinite list of user pictures) If you guys would like, I could just tell you what the app is so you can download it off the Google Play Store and see for yourself how it just becomes slower the more you scroll (email me at meatyoaker001@gmail.com). |
Wow, yours is using an incredible amount of memory -- but still shows the same trend that I'm experiencing. One thing I see at an extreme level on yours is the # of Views. |
@booboothefool that's with FlatList? Something is definitely broken there. Sample code would be helpful. |
So You have a comment that says you tried the default value - were the memory and view numbers exactly the same in that case? I would expect the default to work much better and save your memory. You can also set |
@sahrens I hope I'm that stupid. XD Maybe I was just imagining using the default props? :) Either way I think something changed: Using this code:
I made a video of the and here are the results shown at the end of the video: I definitely noticed a performance improvement. The memory and views are going up, however my app isn't turning to complete mush anymore. Overall, I think I can work with this. Does everything look right to you from my code / video / screenshot? What about you, @jasongrishkoff ? |
@booboothefool your memory usage went from 186mb to 359mb -- that's very high, and it's likely that as soon as you move to another app, Android will automatically garbage collect your app. |
Yeah, seems like I spoke a bit too soon. Noticed the app slowed down a ton once I added everything else back (images, ads, calculations e.g. Birthday -> Age). (I'll make another video when I wake up. The slowdown is noticeable by just adding images ) |
Yeah, 400MB is still a little high - what device are you running on? The heap and cache sizes will vary depending on the device memory. The view count is much more reasonable, but also a bit high. You can try dialing down the But note that the live memory number is going to be much higher than the background number. That 359mb includes GPU texture buffers and other caches that should be cleared when the app is backgrounded. It also might take a while for the JS Garbage collector to trigger a cleanup and release the memory back to the operating system. Memory is a very complex issue. Have you tried doing similar analysis with other apps? What happens if you scroll through the same amount of content in the other apps, like Twitter? |
@sahrens Hello friend. Thanks for your response. ^^ I am using a Samsung Galaxy S6 running Android 6. I tried adding some of my pictures back and besides that, the only code change to
I noticed that using a smaller Another issue I'm seeing is that using
https://www.youtube.com/watch?v=y1HDH5wkFT0 On my live app, I am rendering an ad every 12 items using |
Does Some more perf tips:
|
You're right -- FlatList is performing a heck of a lot better with __DEV__
mode disabled. I created a release variant and am testing that on my
Android device -- it's behaving a lot better, and the memory is 1) staying
reasonable; 2) cleaning up a bit when activity stops (eg, app is
backgrounded or I stop scrolling).
My React Native app is still hanging around 120mb, which puts my app as the
highest non-Android user of memory -- a prime candidate for memory cleanup
when necessary. Twitter opens up at 141mb and after scrolling a bit jumps
to 160mb. After closing it, it drops down to 100mb. But... in the process
of taking those memory snapshots, I noticed that Android cleaned up /
closed my React Native app, which is the crux of the problem I'm having ---
a music app shouldn't close in the background :(
From here, my focus will be on reducing the overall memory footprint of
each item in my list. I'll keep an eye on general performance with the
lists, but otherwise, this seems to be performing significantly better with
regards to stemming leaks!
…On Fri, Mar 3, 2017 at 6:44 AM, Spencer Ahrens ***@***.***> wrote:
Does ListView not use more memory than FlatList? Or is FlatList better on
memory, but more sluggish than ListView? Wth a gigantic windowSize, like
you had before, or with enableVirtualization={false}, they should have
pretty similar performance. Also note that debug is a massive perf hit,
so make sure to turn that off (and also make sure you are not in __DEV__
mode) when you are evaluating performance.
Some more perf tips:
- Try implementing shouldItemUpdate. I don't know what your helper
thing is doing, but ideally you can do === reference checks on the
results it gives back to tell if they have changed, otherwise you might
want to compare the object ids if the results themselves are unlikely to
change? Depends on your product logic.
- Shadows can be quite expensive to render - does it help to get rid
of them? If it helps a lot, then you should use a shadow image asset
instead of generating them programatically.
- What does it mean for your card height to be 35% when they are
inside an infinite list? That seems a little weird and might affect perf?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#12512 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAW6U7XU4YziKnZ_QF5jrMmWgbwMyDpwks5rh5qcgaJpZM4MIds6>
.
--
Jason Grishkoff
Founder of Indie Shuffle <https://www.indieshuffle.com/> and SubmitHub
<https://www.submithub.com/>
----------------------------------------
Twitter: @indieshuffle <http://www.twitter.com/indieshuffle>
Facebook: facebook.com/indieshuffle <http://www.facebook.com/indieshuffle>
Why we don't take premieres
<http://www.indieshuffle.com/news/premiering-songs-and-why-we-ve-stopped/>
|
For a music app there may be special APIs and maybe some native code you need to write to make it a truly great experience. For example, you could save state to disk and then completely toss the JS context and all your views on background and/or when you receive a memory warning and the music could keep playing with a native module.
On Mar 2, 2017, at 10:36 PM, Jason <notifications@github.com<mailto:notifications@github.com>> wrote:
You're right -- FlatList is performing a heck of a lot better with __DEV__
mode disabled. I created a release variant and am testing that on my
Android device -- it's behaving a lot better, and the memory is 1) staying
reasonable; 2) cleaning up a bit when activity stops (eg, app is
backgrounded or I stop scrolling).
My React Native app is still hanging around 120mb, which puts my app as the
highest non-Android user of memory -- a prime candidate for memory cleanup
when necessary. Twitter opens up at 141mb and after scrolling a bit jumps
to 160mb. After closing it, it drops down to 100mb. But... in the process
of taking those memory snapshots, I noticed that Android cleaned up /
closed my React Native app, which is the crux of the problem I'm having ---
a music app shouldn't close in the background :(
From here, my focus will be on reducing the overall memory footprint of
each item in my list. I'll keep an eye on general performance with the
lists, but otherwise, this seems to be performing significantly better with
regards to stemming leaks!
…On Fri, Mar 3, 2017 at 6:44 AM, Spencer Ahrens ***@***.******@***.***>> wrote:
Does ListView not use more memory than FlatList? Or is FlatList better on
memory, but more sluggish than ListView? Wth a gigantic windowSize, like
you had before, or with enableVirtualization={false}, they should have
pretty similar performance. Also note that debug is a massive perf hit,
so make sure to turn that off (and also make sure you are not in __DEV__
mode) when you are evaluating performance.
Some more perf tips:
- Try implementing shouldItemUpdate. I don't know what your helper
thing is doing, but ideally you can do === reference checks on the
results it gives back to tell if they have changed, otherwise you might
want to compare the object ids if the results themselves are unlikely to
change? Depends on your product logic.
- Shadows can be quite expensive to render - does it help to get rid
of them? If it helps a lot, then you should use a shadow image asset
instead of generating them programatically.
- What does it mean for your card height to be 35% when they are
inside an infinite list? That seems a little weird and might affect perf?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#12512 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAW6U7XU4YziKnZ_QF5jrMmWgbwMyDpwks5rh5qcgaJpZM4MIds6>
.
--
Jason Grishkoff
Founder of Indie Shuffle <https://www.indieshuffle.com/> and SubmitHub
<https://www.submithub.com/>
----------------------------------------
Twitter: @indieshuffle <http://www.twitter.com/indieshuffle>
Facebook: facebook.com/indieshuffle<http://facebook.com/indieshuffle> <http://www.facebook.com/indieshuffle>
Why we don't take premieres
<http://www.indieshuffle.com/news/premiering-songs-and-why-we-ve-stopped/>
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#12512 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABcJx0BkpihFIdY6czPgFN0QPCCrXOYUks5rh7TAgaJpZM4MIds6>.
|
We're getting into unrelated territory, but how does one toss views and context on background? Just monitor AppState and set the main component to be null when state is background? Right now I'm using mobx + react-native-music-control to handle the playlist component, and it works just fine when the app is backgrounded. It's just that the app doesn't shed any memory -- it hangs around 100mb+, and I reckon I'd need to get it down to ~75mb to convince Android not to kill it quickly. |
That might help, yeah. You also might want to do some research on native Android development and might have to write some Java to get a world-class music player experience. Have you built anything similar with something like Cordova? How does it fair memory-wise, especially in the background? |
I think music playback should also keep your app prioritized and less likely to get killed by the OS in the background. Are you seeing otherwise? Might want to reach out to the react-native-music-control maintainers, or ask on stack overflow. |
Edit Going to play around with this in release variant a bit more - results below were with dev. The music player experience is pretty solid -- they've done a great job with the aforementioned library. My only problem right now is that my React Native app is quite lean (122 views on fully-loaded home screen according to meminfo), and yet still uses more memory than any other app on my Android device -- even when it's just a basic project (~70MB) with no FlatList or navigation or anything imported at all. A straight-up Hello is all. WhatsApp for comparison idles at 25MB and when active tends to peak around 75MB. If my baseline for a nothing-app is 70mb, it's problematic because anything I add from there is going to increase it. I also observe that when I've backgrounded my app, the amount of memory being used is barely reduced -- maybe 5% over the course of ~20 seconds. If I was using 120MB in the foreground, this means a background app ends up holding onto ~114MB, which puts it at the top of the stackrank of apps open on the Android device, and therefore #1 to be killed if the OS needs to free up memory for another app. Setting the main component to = null brings the # of Views displayed in meminfo from 122 down to 7... and yet the memory still only goes down 5%. Sorry for going so off-tangent given this was originally a ListView conversation. My testing so far indicates that the memory leak issue has been solved by FlatList, which eliminates a huuuge bottleneck. Just need to get the baseline down, or figure out how to shed memory when backgrounded. |
Also make sure you're doing an optimized release build of the native code when making comparisons.
On Mar 3, 2017, at 10:32 AM, Jason <notifications@github.com<mailto:notifications@github.com>> wrote:
The music player experience is pretty solid -- they've done a great job with the aforementioned library. My only problem right now is that my React Native app is quite lean (122 views on fully-loaded home screen according to meminfo), and yet still uses more memory than any other app on my Android device -- even when it's just a basic project (~70MB) with no FlatList or navigation or anything imported at all. A straight-up Hello is all. WhatsApp for comparison idles at 25MB and when active tends to peak around 75MB.
If my baseline for a nothing-app is 70mb, it's problematic because anything I add from there is going to increase it.
I also observe that when I've backgrounded my app, the amount of memory being used is barely reduced -- maybe 5% over the course of ~20 seconds. If I was using 120MB in the foreground, this means a background app ends up holding onto ~114MB, which puts it at the top of the stackrank of apps open on the Android device, and therefore #1<#1> to be killed if the OS needs to free up memory for another app.
Setting the main component to = null brings the # of Views displayed in meminfo from 122 down to 7... and yet the memory still only goes down 5%.
Sorry for going so off-tangent given this was originally a ListView conversation. My testing so far indicates that the memory leak issue has been solved by FlatList, which eliminates a huuuge bottleneck. Just need to get the baseline down, or figure out how to shed memory when backgrounded.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub<#12512 (comment)>, or mute the thread<https://github.com/notifications/unsubscribe-auth/ABcJx8H8N4efr9sYqa-L3DAXK1HmtdmFks5riFyCgaJpZM4MIds6>.
|
Maybe related to #11809? |
I played around with FlatList on iOS with 'full-screen' images in a list and a small windowSize of 3. Memory usage climbs linearly until it hits a threshold where it no longer increases. From enabling debug it it would appear it initially renders a few pages worth of views before the 'windowing' behavior kicks in (nice to see this behavior working :)); the debug visuals would suggest these initial views are never removed. Video of the behavior: https://www.youtube.com/watch?v=s_YUMfb__ms @sahrens I'm not sure if you've any thoughts? :) edit: my mistake, it looks like I just described the VirtualizedList prop 'initialNumToRender' exactly! |
Sounds like you're still using the default I should also add to the docs that the |
… `initialNumToRender` Summary: Should help with some common pitfalls, e.g. #12512 (comment). Reviewed By: yungsters Differential Revision: D4781833 fbshipit-source-id: 3dec2f0c444645ad710e9ed81390636da4581f0f
… `initialNumToRender` Summary: Should help with some common pitfalls, e.g. facebook#12512 (comment). Reviewed By: yungsters Differential Revision: D4781833 fbshipit-source-id: 3dec2f0c444645ad710e9ed81390636da4581f0f
… `initialNumToRender` Summary: Should help with some common pitfalls, e.g. facebook#12512 (comment). Reviewed By: yungsters Differential Revision: D4781833 fbshipit-source-id: 3dec2f0c444645ad710e9ed81390636da4581f0f
Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally! If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:
If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution. |
Hi there, I'm using RN 0.41.2 on an Android device (not emulator). I've created a really simple ListView component. As I scroll down this list, the memory used by the app increases linearly. If I background the app, this memory doesn't get cleaned up at all.
While the code below is simple, you can imagine how out-of-hand this gets on a ListView that renders more-detailed rows (including Image and TouchableOpacity). The problem is that the app I'm building is a music streaming app. If I scroll through ~3 pages of tracks, it bring the app's total consumption up to ~150MB of ram (from an initial boot of 90MB), which makes it the #1 candidate for Android to garbage collect if another app takes the foreground and requires more memory (eg, you want to browse Chrome while listening to the music app in the background). Without the ListView, my app uses up ~55MB -- a number similar to the one generated by the simple component below.
I've tried this with the new/experimental FlatList component, and I get similar - if not worse - results as far as memory consumption. This is the main thing holding me back from rolling out my React Native version to production (on an app with 500,000+ installs).
Screenshots below created using "adb shell dumpsys meminfo -a com.awesomeproject"
The text was updated successfully, but these errors were encountered: