Managing Memory Best Practices in Lazy Loaded App?


#1

Edit: just wanted to add a TLDR - it would be nice if there was a blog post from the ionic team about managing memory in ionic apps! Thanks!

Hey everyone, I’m making good progress on my app and I’m quite happy with load times and responsiveness after making the shift to lazy loading, but now I’m trying to continue optimizing and my current goal is to reduce memory usage.

I’ve made some other posts on here about my app but basically it’s big - almost 250 pages big! Each of these pages has text, grids, and some pages have images. The grids all link to small (3 second) audio files that I’m loading, playing, and unloading with ionic nativeAudio.

I load my home page and base memory usage is around 200 megs, which is larger than I think is ideal but probably fine for most phones/tablets sold in the last few years. If it stayed around 200 megs I would be quite satisfied.

The problem is that for some reason memory usage creeps up as I go from page to page, following a pattern of two steps forward and one step back. I thought that ionic would automatically clear out old data/pages on ionViewDidLeave, but is there some sort of clearing command that I need to execute so that it doesn’t cache all of the old pages in the navigation stack into memory?

I am manually unloading all audio files on ionViewDidLeave(), but I can’t think of what else might be increasing memory usage. My app, though it has many pages, is pretty simple and I can’t imagine that the individual pages of text/grids are very resource intensive. CPU usage sits around 0-4% except with a small spike on page changes. I’m not using the network at all, everything is stored locally, and memory is the last optimization that I need to focus on.

Thanks in advance for any advice!


#2

Pages stay in memory until popped off the nav stack. If you’re going forward from 1-250, you’re going to have a bad time. To choose a number off the top of my head with no justification, I wouldn’t have any navcontroller deeper than 10 or so. Alternatively, you could remove pages manually using the remove command. But if you want something fully paginated that behaves like a Kindle, you should probably store your format data in a json, and read from it as needed from one of a handful of pages intended to present information of that sort.


#3

Ok thanks for the feedback, Aaron. I didn’t know that pages weren’t cleared out unless manually cleared so I’ll have to change my code to reflect that.

I have 30 lessons that are 7-10 pages each so I can just clear out the nav stack when users go to the home/table of contents, which users do between lessons.

I still think some sort of blog post about how ionic manages memory would be insightful!


#4

Is there a reason you can’t just use setRoot()? Does that help?


#5

Does that clear out the whole nav stack when you set root? I read the documentation for nav controller and read something about a ‘new’ nav stack but I wasn’t sure if that meant that the old one was gone or if there was just a second stack created next to it.

So user nagivates to HomePage and then I put in the type script:
ionViewDidLoad{
this.navCtrl(setRoot())
}

That’s a pretty easy fix!


#6

I was thinking more in terms of replacing all your push() calls with setRoot(). If the operation of “going back” is relatively rare, there isn’t much benefit to having the navigation stack.


#7

Ok that makes sense. My app is a digital textbook so it’s good if users can go back within a single lesson in case they want to re-read something or check a vocab item that they’ve forgotten, so I need to keep the push/pop structure within individual lessons but I will start to clear them out when navigating to the root page.

So you can use the setRoot() command as a substitute for pushing a new page?


#8

I think of setRoot() as "wipe entire navigation stack, and then push()".[quote=“EvanW, post:7, topic:90167”]
I need to keep the push/pop structure within individual lessons
[/quote]

That would probably be easiest to code, but if this resource starvation issue becomes really critical, I think you still have the option of only using setRoot() (which effectively means you’re manually doing the NavController's job).


#9

Yeah I’ve been doing some memory testing trying to max out what is likely for a user by going from page to page and even with 40 pages in the nav stack the memory usage doesn’t go above 325 or 350 MB, which is high but not awful. I’ll switch over to setting root between lessons and see how that does. Ideally I’ll keep the pops within lesson but we’ll see based on memory use!

Thanks so much for taking the time to explain this!


#10

I had some similar trouble recently. My app has a header component with a subscription to a variable in a shared service. Everytime I navigated to a new page the component’s constructor was called, so after 10 navigations I had 10 new subscribers. That’s clearly a memory hog.
Had to change my navigation to use setRoot instead of push, because views​ don’t get destroyed (no ngOnDestroy called), and as components are currently unaware of their active or not-active state you need a destroy method to call all unsubscribes.


#11

You could subscribe in ionViewWIllEnter, and unsubscribe in ionViewWillLeave(), or let the async pipe handle that for you.


#12

Tried that but my component wasn’t catching any page events, tried them all. Only worked after implementing ngOnDestroy and modifying the navigation to use setRoot.


#13

Components don’t get page events; only pages do.


#14

Yep, but components should be somehow aware of their own active/not active state, no matter what kind of navigation your app has.
I filed a feature request for this on Ionic’s Github.