-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Fix high memory usage in Reader #21120
Conversation
@kean Hey, |
@alpavanoglu it looks like it worked, thank you! Should I remove the remaining imports?
|
📲 You can test the changes from this Pull Request in WordPress Alpha by scanning the QR code below to install the corresponding build.
|
📲 You can test the changes from this Pull Request in Jetpack Alpha by scanning the QR code below to install the corresponding build.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the work! I first reviewed the code and then will move on to testing.
I agree with using a single cache, especially if we want to keep the memory usage under control.
MemoryCache
looks straightforward, heavily utilizing NSCache
. It looks like AnimatedImageCache
was also simplified by reusing MemoryCache
and removing extra calculations for an acceptable cost limit.
I lack experience implementing such image caching systems so I cannot give much expert insight. However, the implementation of MemoryCache
looks understandable and straightforward. My main concern was about setting MemoryCache
as a default image cache for AlamofireImage
. Since ImageLoader
uses AlamofireImage
I wondered if there's anything we might miss by using MemoryCache
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested the solution
MemoryCache
caching works well for static images and GIFsMemoryCache
also as expected acts as a default cache forAlamofireImage
andWordPressUI
- Memory footprint rose to about 700MB for me before going down and settling around 600MB. With large gifs, it spiked up to 900MB+ a couple of times and then quickly dropped. As I read in NSCache documentation:
This is not a strict limit, and if the cache goes over the limit, an object in the cache could be evicted instantly, at a later point in time, or possibly never, all depending on the implementation details of the cache.
I tested both on the trunk and on this branch but both produced similar results after a similar amount of usage and similar sites. I will do more testing tomorrow. Did you use some particular media-heavy sites yourself?
It will also be good for at least second set of eyes to look at this PR.
I can look over this tomorrow. @kean, do you think it makes sense to try to target Monday's beta? |
I searched for "photos" and "GIFs" and browsed more or less randomly. The worst-case scenario is when you browse a mix of GIFs, regular photos, and avatars. The GIFs have their own cache in the trunk, which keeps growing almost indefinitely. I quickly hit ~1.8 GB or RAM, and then the memory clears after a memory warning. I tested on iPhone 13. You can look for application_low_memory_warning in the console. I just re-tested it again and got four memory warnings in a span of around 5 minutes. I don't think Watchdog can kill an app when you have a debugger attached. In production, that would've been a crash. The memory warnings are the main thing to look for.
In the trunk, the app uses the default I don't expect this fix to be a panacea, but it should at least reduce the number of these worst-case-scenario memory warnings and crashes. |
I'd say yes. I kept the number of changes to the minimum to reduce the risk of regressions. In the worst-case scenario, this small change may end up being not enough, but it should be an improvement. |
To summarize, before, the app had the following caches:
Now these caches were replaced by a single cache with a 256 MB limit. The expected result of this change is that it will reduce the number of memory warnings, especially when browsing Reader with a mix of regular images, user avatars, and GIFs. P.S. The limits are imprecise because it's impossible to actually calculate how much memory an image takes in memory, how much memory is needed to render it on screen, and how often the system clears the textures used for rendering. So think of these numbers as more relative than absolute. |
Update: I found three more caches: two in |
I was curious how much browsing would lead to an actual crash on my device. So I browsed images and gifs today for about 15 minutes but couldn't make it crash. I'm on an iPhone 11, so it has 4GB of RAM. By some estimates, apps can use 60% of device RAM which would be 2.4GB in my case. Since you mention casual browsing could reach 2GB, and I did some intense browsing and didn't see a crash, it's possible that:
I'm not sure if the app could go beyond the RAM limit by using paged memory, so perhaps 4GB is not the upper limit on my device. It's clear this PR will help reduce crashes, I wanted to explore how much so, hence the above observations. |
I'll prioritize this tomorrow to review since today I only tested the app store version to try to reproduce an actual crash in the Reader. |
The following PR addresses the high memory usage when displaying GIFs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through the code and it looks good, although I haven't tried to compare the tradeoffs of the new NSCache
with the older caching mechanisms. I did see this comment about this where it's stated that it should be an improvement.
I'll do some more testing today and leave another review.
3a47ef0
to
5ffdcbc
Compare
Hey @kean, I don't think we'll get this merged today. It's not a big code change, but as you mention above, it affects images throughout the app, not just Reader (on that note, the PR title seems out of date now). This is how I see the app's caching right now (based on this Slack thread:
Does that sound accurate to you? If we're changing the caching of pretty much all the images in the app, can I suggest listing out where in the app (including outside Reader) that you've tested for regressions? It would also be useful to list which parts of the app are not affected by this change. For example, the editor and the avatars shown when @-mentioning someone. |
A more detailed breakdown is linked to the recent post on memory caches in Jetpack Mobile. The list of the affected components is going to be in dozens. My approach was to provide a replacement with the exact same API and behavior (except for the size limits). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I retested and re-reviewed the changes once again.
I also smoke-tested other parts of the app and I haven't identified places where image loading was an issue. Address ongoing discussions and concerns before merging 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I smoke-tested the JP app and didn't run into any issues with this PR. Code-wise, as you mention above, this change unifies caches (and adjusts their sizes) without fundamentally changing the app.
It looks safe and I can't see any issues when testing. I didn't measure the performance improvement and instead relied on @staskus review of that, #21120 (comment).
I've come back from my vacation. It looks like there has been good progress here. Please let me know if you want me to review and/or test as well. |
5ffdcbc
to
7cffec9
Compare
Related Issue: #20989
This PR introduces a
MemoryCache
singleton for storing images cached by all the image-loading subsystems in the app, of which there are a few.Prior to this change, if you were casually browsing the Reader, you could easily reach 2 GB or higher memory usage, which is likely the reason for the frequent Watchdog terminations.
RCA: There are multiple subsystems that manage image loading in the app, each with its own cache. In some cases, the caches had no count and cost limit. More info: p1689355268133699-slack-C05CANZ2B6F.
After the change, the memory usage fluctuates at a quite respectable 400 MB limit, and the cache consistently gets trimmed as you use the app.
GIF
GIF data is now also stored in the same
MemoryCache/shared
instance.Some blogs post heavy GIFs (20 MB+), and when I encountered one, the memory usage spiked to around 1 GB, which is expected for GIFs format. But when you leave such a site, the memory usage slowly wanes.
To test:
The scenarios I tested include browsing the posts in the Reader and opening post details.
Regression Notes
PR submission checklist:
RELEASE-NOTES.txt
if necessary.UI Changes testing checklist: