简体   繁体   中英

How to measure Android app data size and identify storage leaks?

I made a small Android app and have been using it for a while now. I noticed that, in the settings, on the "data" line of my app's characteristics (I am not interested in analysing the amount shown on the "application" line nor on the "cache" line), it shows about 20 MB, which seemed a lot to me. I am afraid the app has storage leaks (ie that it produces data that is never erased).

I decided to investigate and measure what might take that much space. I use pretty much all the available storage options for this app: SQLite DB, internal files, external files, shared preferences (and cache files including Glide picture loading).

So far, thanks to a question on SQLite DB , I found that my DB file takes about 500 kB. I found by scanning recursively the files and folders in the folder getFilesDir() that I use 10 kB of data in internal and app-private external files. I have not analysed Shared Preferences size yet, but I store less than 20 key/value pairs.

Exploring the folder getCacheDirs() I also found that Glide uses about 3 MB of cache (close to what the Android settings app tells).

My question is, which leads did I miss to find where this 19.5 MB of data I cannot locate? Did I forget some kind of storage that might take space? And, more generally, are there tools to analyse storage leaks (ie data produced by the app that might never be erased)?

Following @James suggestion, I started exploring the different folders, and after discussing the issue with a colleague and trying to explore many folders, I finally found that most of the data came from the cache of a former Webview I had. I am posting all my investigation, hopefully it will help.

I executed the following code when the app starts, calling analyseStorage(this) from my main activity:

public void analyseStorage(Context context) {
  File appBaseFolder = context.getFilesDir().getParentFile();
  long totalSize = browseFiles(appBaseFolder);
  Log.d(STORAGE_TAG, "App uses " + totalSize + " total bytes");
}

private long browseFiles(File dir) {
  long dirSize = 0;
  for (File f: dir.listFiles()) {
    dirSize += f.length();
    Log.d(STORAGE_TAG, dir.getAbsolutePath() + "/" + f.getName() + " uses " + f.length() + " bytes");
    if (f.isDirectory()) {
      dirSize += browseFiles(f);
    }
  }
  Log.d(STORAGE_TAG, dir.getAbsolutePath() + " uses " + dirSize + " bytes");
  return dirSize;
}

What is important is to scan specifically context.getFilesDir().getParentFile() which matches the folder /data/data/my.app.package/

After executing that code, I had the following logs:

D/storage﹕ /data/data/my.app.package/lib uses 0 bytes
D/storage﹕ /data/data/my.app.package/cache uses 3371773 bytes
D/storage﹕ /data/data/my.app.package/databases uses 483960 bytes
D/storage﹕ /data/data/my.app.package/shared_prefs uses 604 bytes
D/storage﹕ /data/data/my.app.package/app_webview uses 9139469 bytes
D/storage﹕ /data/data/my.app.package/files uses 7723 bytes
D/storage﹕ /data/data/my.app.package/app_ACRA-approved uses 0 bytes
D/storage﹕ /data/data/my.app.package/app_ACRA-unapproved uses 0 bytes
D/storage﹕ App uses 13003529 total bytes

What I could see is:

  • The cache, used only by Glide for picture loading, takes 3MB
  • The SQLite database takes 500kB
  • The shared preferences take 600B
  • The cache for all the Webviews I used to have still takes 9MB
  • The rest of the files, under files and other folders, is mostly used by ACRA for bug tracking and take 10kB

In the end, I finally discovered that most of my data went to Webview cache, actually not stored explicitly as cache. I deleted these files and it actually reduced the size of my app by 20MB, even more than listed above. I now know what order of magnitude my app's data takes.

There is no storage leaks.

You didn't count odex (dalvik) or oat (android runtime) file in. They are usually located at

/data/dalvik-cache/xxx.odex
/data/dalvik-cache/<target-architecture>/xxx.oat

These files are generated by system for optimization during installing time.

Also you didn't count your APK file in which located at

/data/app/xxx.yyy.zzz.apk

The directories or files are not accessible from adb shell if the device is not rooted.

I think the storage usage show at settings include the following three parts

/data/data/xxx.yyy.zzz
/data/app/xxx.yyy.zzz.apk
odex or oat file

So the storage size you counted under /data/data/xxx.yyy.zzz is always less than the total size in settings.

You can use MAT TOOL for optimizing memory/size issues in your app.It displays which part in your app using more memory.

Run you app in Android-studio and Go to Tools->Android->AndroidDeviceMonitor ,run your scenario and in device monitor click to download your app .hprof file by follow the image I attached below 下载.hprof文件

After that you need to convert Android-studio .hprof file to Eclipse Mat supported .hprof file by using hprof-conv.exe inside sdk->platform-tools and follow the cmd in your CMD promt

F:\Android_Studio_SDK\platform-tools>hprof-conv "C:\Users\Bala\Desktop\your_AS_file.hprof" "C:\Users\Bala\Desktop\MAT_File_Name.hprof"

And in MAT Tool go to File -> OpenHeapDump to open your .hprof file,It will show your app memory utilize by package,class,object..etc;

Some referral link for learn about MAT Tool
link 1
link 2

You can use a library like Leak Canary to automatically detect all memory leaks inside your app: https://corner.squareup.com/2015/05/leak-canary.html

You can also go to the DDMS in Android Studio and get more information of the storage in your app without coding anything. However, most of the leaks would be detected by Leak Canary.

Hope it helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM