Memory Management for App


#1

I have a requirement for my app to update the list in every few seconds. I am using REST call to get the data from server, process it (some filters and mapping) and assign to RadlistView. I have noticed that after 5-10 minutes app becomes very unresponsive and list actually freeze to scroll.
When I check the memory, it looks kike app used memory is increasing on every REST call.
Below is the code that I have used to check the memory
var mi = new android.app.ActivityManager.MemoryInfo();
var activityManager = application.android.context.getSystemService(android.content.Context.ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
let usedMemory = mi.totalMem - mi.availMem;
// console.log("availMem in bytes: " + mi.availMem);

    // console.log("availMem in bytes: " + mi.availMem);
    console.log("Percentage usage: " + (usedMemory / mi.totalMem)*100);
    // console.log("Available memory (megabytes): " + mi.availMem);
    console.log("Used memory (megabytes): " + (usedMemory/1000000));

As I am using page-router-outlet, ngDestory is not getting called every time when user moves away from this page. But I have tried make my list source null/new array on page unload. I have also tried to call GC on page unload but no success.

Has anyone any suggestion to improve this?


#2

@nmongiya do you by any chance keep storing the same list data in a variable that never gets collected? Perhaps you are adding the same items over and over to the radlist after every REST response? Just some things to think about.


#3

Thanks for your suggestion @Pete.K , Although I am trying to collect as many as objects as I can before assigning them new data. Memory usage is always increase when I make a REST api call to load the data. (Even I have tried with a very basic sample with list and pulltorefresh mechanism, )


#4

I have created a new project using tns create myApp --ng and just made the change to load the data, instead of loading item locally I am making a rest call to load the data.

Another interesting point to note is memory consumption is increasing after each REST call (it returns ~135 kb data). Here is my log after few pull to refresh
used memory is 569.884672 and Percentage usage in : After pull to refresh 35.89
JS: used memory is 578.424832 and Percentage usage in : After pull to refresh 36.43
JS: used memory is 580.980736 and Percentage usage in : After pull to refresh 36.59
JS: used memory is 581.267456 and Percentage usage in : After pull to refresh 36.61
JS: used memory is 581.640192 and Percentage usage in : After pull to refresh 36.63
JS: used memory is 582.750208 and Percentage usage in : After pull to refresh 36.70
JS: used memory is 585.150464 and Percentage usage in : After pull to refresh 36.85
JS: used memory is 585.146368 and Percentage usage in : After pull to refresh 36.85
JS: used memory is 580.161536 and Percentage usage in : After pull to refresh 36.54
JS: used memory is 581.644288 and Percentage usage in : After pull to refresh 36.63
JS: used memory is 583.467008 and Percentage usage in : After pull to refresh 36.74
JS: used memory is 569.085952 and Percentage usage in : After pull to refresh 35.84
JS: used memory is 572.526592 and Percentage usage in : After pull to refresh 36.06


#5

Can you create a playground example to demonstrate your issue? So it will be easy for us to understand what is going wrong and help you with a solution.


#6

Thank You @manojdcoder . My Playground is almost ready but the problem is I am using below code to detect memory.
public checkForMemory(page: string) {
var mi = new android.app.ActivityManager.MemoryInfo();
var activityManager = application.android.context.getSystemService(android.content.Context.ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
let usedMemory = mi.totalMem - mi.availMem;
console.log(used memory is ${(usedMemory / 1000000)} and Percentage usage in : ${page} ${((usedMemory / mi.totalMem) * 100).toFixed(2)});

}

For that I am declaring ‘android’ on top before @component like this
declare var android: any;

It works fine on IDE but on playground it gives error
ERROR: ERROR ReferenceError: Can’t find variable: android


#7

Here you go


#8

Points of improvements.

  1. From my observation, your server takes at least 1 to 1.5 sec to process a request at a time. I doubt it can take even more time if there are 100s of concurrent request from different users. So you must wait for the existing request to complete before you do .notifyPullToRefreshFinished()
public onPullToRefreshInitiated(args: ListViewEventData) {
        this.listView = args.object;
        this._loadData().then((data) => {
            this.items = data;
            this.listView.notifyPullToRefreshFinished();
            this.checkForMemory('After pull to refresh');
        });
}
  1. Looks like you are loading 100s of records at one shot (279 to be precise). This is kind of overload, always load 10-25 records based on your screen & row sizes, load more element when user scrolls down.

#9

I think this piece of code is your problem. Where do you unsubscribe from the observable? This usually leads to a memory leak.

private _loadData() {
    let items;
    return new Promise((res) => {
        this.itemService.getOrders().subscribe((data) => {
            console.log(data['deliveries'].length)
            items = data['deliveries'];
            res(items);
        })
    });
}

Idea of improvements:

  1. If you really want to work with promise, use the .toPromise() on the getOrders() observable, instead of creating a new promise.
  2. When using .subscribe(), you should always have a call to .unsubscribe (in a ngOnDestroy hook for example)
  3. Here, you work with a list view, it can handle the observable if you do something like [items]=“items | async”

Learn a bit of RxJs and everything will be fine.


#10

Thank you @manojdcoder and @fthuin , I am working on your suggestions and will keep you guys posted.


#11

@manojdcoder, @fthuin looks like there was an issue with the template