如何找到内存泄漏的根?

时间:2011-05-18 14:32:20

标签: java android memory-leaks heap out-of-memory

我的应用程序基本和图像编辑器。有一个欢迎页面可以打开主要活动。如果在主要活动正在运行时方向发生变化,则内存消耗量会翻倍并保持不变。如果我关闭主要活动,请返回欢迎活动并再次启动主要活动同样的问题不会发生。我认为所有这些都表明内存泄漏,我已经调查了自己,但无法找到为什么应用程序泄漏内存。我正在使用应用程序上下文,我的应用程序中没有静态字段。我试图转储堆并用MAT分析它,但我找不到任何好的东西。我希望有人能告诉我正确的方向,找到内存泄漏的根源或其他可能的问题解释。

5 个答案:

答案 0 :(得分:3)

Google I|O 2011 conference presentation涵盖了此特定方案。我建议观看演示文稿,因为它可以帮助您更好地使用MAT找到问题。

答案 1 :(得分:2)

请记住,在JVM中(甚至在我不能相信它不是像Davlik那样的JVM中),您使用的许多项目并不完全在您的控制之下。因此,正确的方法是找到一种方法来验证您的代码没有内存泄漏,然后您就会知道如果内存开花,可能是某个外部子系统,或者应用程序实际内存需求的某些预期结果。 / p>

根据您的描述,很容易就是显示渲染只是为每个屏幕方向保留一个延迟构建的缓存内存缓冲区。

我只提到这个,因为你已经(从你的帖子中)比较了堆转储,如果堆没有显示对象累积的趋势,那么它很可能是库实现中包含的一些项目。我知道这是一个非常一般的经验法则,并不适用于大多数程序(因为它们可能确实包含真正的内存泄漏),但是当其他选项耗尽时,它可能会被调查。

如果你真的想验证一个特定的库是否保留了屏幕方向的缓存副本,你总是可以编写一个小的“测试”程序,它缺少所有混淆因素(比如程序的其余部分)并了解它在屏幕方向转换方面的表现。

就使用VisualVM而言,它非常适合检测用户空间内存泄漏;但是,由于它运行在不同的架构和实现上,因此可能会错过特定于平台的库问题。

答案 2 :(得分:2)

我的应用程序遭受了严重的泄漏,虽然我发现MAT工具很有用,但我发现主要原因是我没有正确管理活动堆栈。我认为最有用的检查方法是使用命令行:

adb shell dumpsys meminfo your.package.name

你会得到像

这样的输出
adb shell dumpsys meminfo your.package.name
Currently running services:
  meminfo
-------------------------------------------------------------------------------
DUMP OF SERVICE meminfo:
Applications Memory Usage (kB):
Uptime: 150876 Realtime: 150875

** MEMINFO in pid 253 [your.package.name] **
                    native   dalvik    other    total
            size:     5404     4103      N/A     9507
       allocated:     5294     3110      N/A     8404
            free:      101      993      N/A     1094
           (Pss):     2346     3737     2198     8281
  (shared dirty):     1964     4644     1480     8088
    (priv dirty):     2204     1856      956     5016

 Objects
           Views:       30        ViewRoots:        2
     AppContexts:        3       Activities:        2
          Assets:        2    AssetManagers:        2
   Local Binders:       13    Proxy Binders:       16
Death Recipients:        2
 OpenSSL Sockets:        0

 SQL
            heap:        0          dbFiles:        0
       numPagers:        0   inactivePageKB:        0
    activePageKB:        0

检查活动计数并在更改方向时观察堆大小更改等。确保您没有启动已在运行的活动的副本。您可以使用您在启动活动时为其提供的标志来控制堆栈。

答案 3 :(得分:1)

VisualVM http://visualvm.java.net/
它是JDK发行版以来的1.6版本。

答案 4 :(得分:0)

如果您的应用程序是图像编辑器并且您看到了这种类型的行为,那么我希望您不会回收Bitmap内存(请参阅http://developer.android.com/reference/android/graphics/Bitmap.html#recycle%28%29)。

当您的方向发生变化且活动被破坏时,您需要找到您的视图正在使用的任何大型位图,然后在其上调用recycle或使用onRetainNonConfigurationInstance方法(请参阅{{3将它传递给新的Activity实例。