20 December 2021 Leave a comment QA
In order to provide the best experience to your app users it’s a great idea to check the memory usage of your app.
ADB (Android Debug Bridge) provides an easy way to fetch a memory usage profile. You can execute ‘adb shell dumpsys meminfo’ to get the whole dump.
But what if you want to automatically check the memory consumption for every new release of your app? And what if you want to check the memory consumption at several places within your use cases?
I guess you’d rather automate the checks.
So here is how you can do it with Repeato.
Repeato provides the JS-Script step feature, which also allows you to execute ADB commands and process the returned information:
const packageName = 'com.google.android.calculator' // <- your app's packagename const getValue = function(lines, keyword){ const linesArr = lines.split('\\n') const theLine = linesArr.filter(line => line.trim().indexOf(keyword) === 0)[0] const cleaned = theLine.replace(keyword, '').replace(/\s+/g,' ').trim() const firstValue = cleaned.split(' ')[0] return parseInt(firstValue) } const meminfo = await deviceConnector.sendAdbCommand('shell dumpsys meminfo '+packageName) // if you want to check certain values: //const nativeHeapMem = getValue(meminfo, 'Native Heap') //const dalvikHeapMem = getValue(meminfo, 'Dalvik Heap') //const dalvikOtherMem = getValue(meminfo, 'Dalvik Other') const totalMem = getValue(meminfo, 'TOTAL') if(totalMem > 40000){ // adjust to your needs! throw new Error('App is consuming too much memory: '+totalMem) } return 'Total memory used (kilobytes): '+totalMem
To reuse this code in several different spots within your test setup, we recommend saving just this single step as a test to your library, so you can import it via a “Sub test step” wherever you might need to check the memory usage within your automation.
Here is a little screencast of what all of this looks like:
More about Android memory usage
Since interpreting the memory dump is far from obvious, here are some explanations of what the different rows and columns refer to. Be aware that every application in Android runs in a separate instance of its own VM (Dalvik or nowadays ART).
Native Heap: represents memory used by the process itself (Ex: Native C mallocs).
Dalvik Heap: represents memory allocated by the VM (Ex: Variables in your Android code).
Dalvik Other: is memory used for JIT and garbage collection.
Android may share memory among several processes (e.g. within common frameworks).
Clean memory: one that hasn’t changed since it was allocated or loaded from storage (Code of your application).
Dirty memory: is space used for computations.
Android does not have a swap mechanism so Dirty memory is also RAM that will be freed when the app exits.
RSS: Resident Set Size: Actual physical memory used (including memory occupied by shared libraries)
PSS: Proportional Set Size: Actual physical memory used (proportional allocation of memory occupied by shared libraries)
App Sumary explained:
Java: Memory from objects allocated from Java or Kotlin code.
Native: Memory from objects allocated from C or C++ code.
Even if you’re not using C++ in your app, you might see some native memory used here because the Android framework uses native memory to handle various tasks on your behalf, such as when handling image assets and other graphics—even though the code you’ve written is in Java or Kotlin
Graphics: Memory used for graphics buffer queues to display pixels to the screen, including GL surfaces, GL textures, and so on. (Note that this is memory shared with the CPU, not dedicated GPU memory.)
Stack: Memory used by both native and Java stacks in your app. This usually relates to how many threads your app is running.
Tags: memory profiling, qa, test automation