如何测量 Android 应用程序数据大小并识别存储泄漏?

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

我制作了一个 Android 小应用程序,现在已经使用了一段时间。我注意到,在设置中,在我的应用程序特性的 "data" 行(我对分析 "application" 行和 "cache" 行上显示的数量不感兴趣),它显示大约 20 MB,这对我来说似乎很多。恐怕该应用程序存在存储泄漏(即它产生的数据永远不会被删除)。

我决定调查和衡量可能需要那么多的东西 space。我用的比较多 all the available storage options for this app: SQLite DB, internal files, external files, shared preferences (and cache files including Glide 图片加载)。

到目前为止,感谢 a question on SQLite DB,我发现我的数据库文件大约需要 500 kB。通过递归扫描文件夹 getFilesDir() 中的文件和文件夹,我发现我在内部和应用程序私有的外部文件中使用了 10 kB 的数据。我还没有分析共享首选项的大小,但我存储了不到 20 key/value 对。

浏览文件夹 getCacheDirs() 我还发现 Glide 使用了大约 3 MB 的缓存(接近 Android 设置应用程序显示的内容)。

我的问题是,我错过了哪些线索来找到我找不到的这 19.5 MB 数据的位置?我是否忘记了某种可能需要 space 的存储空间?而且,更一般地说,是否有分析存储泄漏的工具(即应用程序产生的可能永远不会被删除的数据)?

您可以使用 MAT TOOL 来优化 app.It 中的 memory/size 问题,显示应用中的哪个部分使用了更多内存。

运行 你的应用程序在 Android-studio 并转到 Tools->Android->AndroidDeviceMonitor,运行 你的场景并在设备监视器中点击下载你的应用程序 .hprof 文件 按照我附上的图片以下

之后,您需要使用 hprof-conv.exe 将 Android-studio .hprof 文件转换为 Eclipse Mat 支持的 .hprof 文件 sdk->平台工具 并按照您的 CMD promt

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

然后在 MAT Tool 中转到 File -> OpenHeapDump 打开你的 .hprof 文件,它会显示你的应用内存使用情况包,class,对象..等;

一些推荐 link 以了解 MAT 工具
link 1
link 2

按照@James的建议,我开始探索不同的文件夹,在与同事讨论这个问题并尝试探索许多文件夹后,我终于发现大部分数据来自我以前的Webview的缓存.我正在发布我所有的调查,希望它会有所帮助。

我在应用程序启动时执行了以下代码,从我的主 activity 调用 analyseStorage(this):

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;
}

重要的是专门扫描 context.getFilesDir().getParentFile() 匹配文件夹 /data/data/my.app.package/

执行该代码后,我得到以下日志:

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

我能看到的是:

  • 缓存,仅供 Glide 用于图片加载,占用 3MB
  • SQLite 数据库占用 500kB
  • 共享首选项占用600B
  • 我以前拥有的所有 Webview 的缓存仍然需要 9MB
  • 其余文件,在files和其他文件夹下,主要被ACRA用于错误跟踪,占用10kB

最后,我终于发现我的大部分数据都去了Webview缓存,实际上并没有明确存储为缓存。我删除了这些文件,它实际上将我的应用程序的大小减少了 20MB,甚至比上面列出的还要多。我现在知道我的应用程序数据的数量级了。

您可以使用像 Leak Canary 这样的库来自动检测应用内的所有内存泄漏: https://corner.squareup.com/2015/05/leak-canary.html

您还可以转到 Android Studio 中的 DDMS,无需编写任何代码即可获取应用中存储的更多信息。 但是,大多数泄漏都会被 Leak Canary 检测到。

希望对您有所帮助!

没有存储泄漏。

您没有计算 odex(dalvik) 或 oat(android 运行时)文件。它们通常位于

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

这些文件是系统在安装时为优化而生成的。

你也没有计算你的 APK 文件位于

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

如果设备未获得 root 权限,则无法从 adb shell 访问目录或文件。

我认为设置中显示的存储使用情况包括以下三个部分

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

因此您在/data/data/xxx.yyy.zzz下计算的存储大小总是小于设置中的总大小。