Bryant Harris
Bryant Harris

Reputation: 728

Determining available memory on Android

So one of the challenges on Android is various device specifications (in particular device memory).

I've written my model objects to extensively use Java SoftReferences in a lazy load fashion, so the VM is free to trim not currently used parts of the data model as it sees fit and they are just reconstituted as needed.

However, one challenge in practice with SoftReferences is that they tend to be cleared within a few seconds of become weakly referenced as opposed to hanging around until the VM is low on memory, so they work well in terms of allowing the model to trim, but they don't work as well in that it often means nothing is in memory. Ideally on a device with plenty of memory, you'd let the user benefit from keeping objects in memory.

As a result, it's common to combine SoftReferences with an LRU mechanism, where the LRU keeps a hard pointer to the recently referenced objects. This of course is not ideal since it assumes that you have enough memory for all these hardly referenced objects.

It also makes it a challenge to know what is a good default for the LRU.

In a perfect world, Android would use it's low memory callback as a hint (so I could possibly start with a small LRU, and periodically bump it up until low memory callbacks started occurring then back it off to find a good value for a device), but in my experience this callback never seems to coincide with actual VM memory pressure.

Has anyone come across a reasonable way of detecting that your data model is using too much memory on a particular device?

Upvotes: 11

Views: 1503

Answers (4)

John Dallman
John Dallman

Reputation: 694

Here's a more detailed NDK answer:

Looking at the Bionic LibC source for sysconf reveals that _SC_PHYS_PAGES and _SC_AVPHYS_PAGES are implemented by reading /proc/meminfo, which is maintained by the Linux kernel. The first few lines of that file on the Lenovo Android 7.0.1 device with 4GB RAM I'm using look like this:

MemTotal:        3721064 kB
MemFree:          208108 kB
MemAvailable:    2543032 kB
  • sysconf( _SC_PHYS_PAGES) gives you the MemTotal value, in units of the page size. This seems to be the total memory available to Android for code, data, and so on. It's about 300MB less than the claimed physical RAM on the device I'm using, which may be accounted for by the screen buffer and so on.
  • sysconf( _SC_AVPHYS_PAGES) gives you the MemFree value, in the same units. This appears to be the memory that isn't in use for anything at all. On my 4GB device, it's only about 200MB.

Sadly, there is no sysconf parameter for the far more useful MemAvailable value, which is the RAM that can be made available if required. Apparently this is because MemAvailable was only added to the Linux kernel in early 2014, while the sysconf() support seems rather older than that. MemAvailable is not in a Samsung Android 5.0, but is in Amazon FireOS 5.6 (based on Android 5.1), and a Motorola Android 7.1; I don't know about 6.x.

What I'm planning to do for an NDK test harness (not a app that will be distributed), having got to the bottom of this, is use MemAvailable if it is there, and otherwise use half the physical RAM size. Since I will have to read /proc/meminfo to find out if MemAvailable is there, there's no point in having Bionic LibC read it again if I call sysconf().

Upvotes: 0

Satyam
Satyam

Reputation: 1682

if you want to determine available memory in android , then you can check or go to in perspective - >ddms 2) second thing is you can use memory analyzer tools checked in used and unused memory, you also check availability of memory.

Upvotes: 2

dileping
dileping

Reputation: 1648

If you use Android NDK:

#include <unistd.h>

size_t getTotalSystemMemory()
{
    long pages = sysconf(_SC_PHYS_PAGES);
    long page_size = sysconf(_SC_PAGE_SIZE);
    return pages * page_size;
}

size_t getFreeSystemMemory()
{
    long pages = sysconf(_SC_AVPHYS_PAGES);
    long page_size = sysconf(_SC_PAGE_SIZE);
    return pages * page_size;
}

Upvotes: 1

JPeace
JPeace

Reputation: 86

Would this work?

MemoryInfo mi = new MemoryInfo();
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;

Upvotes: 0

Related Questions