【问题标题】:Android memory leak?Android内存泄漏?
【发布时间】:2011-12-31 17:28:42
【问题描述】:

我认为我的 android 应用程序正在泄漏内存。不过,我不确定这是否是问题所在。

应用程序在打开时经常崩溃,并且 logcat 在尝试加载位图图像时显示“内存不足”异常。

崩溃后,我重新打开应用程序,它工作正常。 Logcat 显示很多“gc”,并且每隔一段时间 JIT 表就会向上调整大小,从不向下调整,直到应用程序因内存不足错误而崩溃。

这听起来像是内存泄漏吗?如果是这样,我该如何定位和关闭泄漏点。

这是我的应用程序的 adb shell meminfo。

** MEMINFO in pid 2691 [com.example.deepcliff] **
                    native   dalvik    other    total
            size:    23264     8839      N/A    32103
       allocated:    12503     3826      N/A    16329
            free:      168     5013      N/A     5181
           (Pss):     2512     1395    13815    17722
  (shared dirty):     2088     1844     5008     8940
    (priv dirty):     2412      224    11316    13952

 Objects
           Views:        0        ViewRoots:        0
     AppContexts:        0       Activities:        0
          Assets:        2    AssetManagers:        2
   Local Binders:       55    Proxy Binders:       13
Death Recipients:        1
 OpenSSL Sockets:        0

 SQL
               heap:      129         MEMORY_USED:      129
 PAGECACHE_OVERFLOW:        9         MALLOC_SIZE:       50

 DATABASES
      pgsz     dbsz   Lookaside(b)  Dbname
         1       14             10  webview.db
         1        6             18  webviewCache.db

 Asset Allocations
    zip:/data/app/com.example.deepcliff-2.apk:/resources.arsc: 17K

【问题讨论】:

  • 首先 - 我假设您的应用程序在刚重新启动的设备上 - 可以在您使用它时加载它需要的所有位图。在activity堆栈上返回它几次会崩溃吗?在这种情况下,您很可能会通过保留对已被破坏的活动实例的引用来泄漏内存。
  • 1.是的,它通常工作正常。它只是在我使用它一段时间后崩溃,然后关闭它并再次打开它。因此,如果它是您提到的方式的泄漏,我在哪里可以找到对我的活动实例的引用。
  • 我很好奇在某些活动中改变方向(很多)是否会影响?这将缩小潜在的错误情况。
  • 我不允许改变方向。它总是垂直的。
  • 如果可能的话,我们能看到发生“内存不足”异常的类吗?新鲜的眼睛可能会在那里发现一些东西。

标签: java android memory-leaks


【解决方案1】:

这里有几篇文章和帖子,可能会帮助您走上正轨:

Allocation tracker,Android SDK 自带的非常有用。阅读 Romain Guy 的文章。它帮助我找到了非常讨厌的泄漏。它还可以帮助您编写更好的软件。例如。我学会了创建更少的对象,使用更多的 StringBuilder,并缓存更多:
What Android tools and methods work best to find memory/resource leaks?

有时您的应用程序非常混乱,以至于您必须重新设计整个应用程序。以下是官方的很好的提示(我最喜欢的是避免创建不必要的对象):
http://developer.android.com/guide/practices/design/performance.html


这是一篇关于解决内存问题的优秀文章:
http://ttlnews.blogspot.com/2010/01/attacking-memory-problems-on-android.html

关于避免内存泄漏的官方文章:
http://android-developers.blogspot.co.uk/2009/01/avoiding-memory-leaks.html

另请阅读:tool to check memory leaks in android


其他人已经指出了位图。这是一篇描述该问题的文章:http://zrgiu.com/blog/2011/01/android-bitmaps-and-out-of-memory-errors/

【讨论】:

  • 代码是否将任何活动或可绘制对象存储到静态变量中?或者它们中的任何一个是否存储在创建它们的类之外?当尝试以这种方式优化内存消耗或分配时,很容易泄漏大量内存。例如。创建活动时将位图存储到静态变量中。然后在每次方向更改时,应用程序都会泄漏内存。
  • 我不这么认为,至少不是故意的。我将再次检查我的代码。感谢您的链接。
  • 好的,所以我有一个用户经常在活动之间切换,这意味着他们可能在 20 秒内切换了 15 个活动。这可能是导致内存不足错误的原因吗?我应该怎么做才能修复它?谢谢!
【解决方案2】:

这不是内存泄漏。 Android 设备的内存量有限,而且您的位图必须太大。您需要找到一种方法来减小位图的大小。我真的不能告诉你更多,因为你没有给我们太多的继续。

【讨论】:

  • 抱歉,我会编辑我的问题。我最大的图像是大小约为 600kb 的 PNG,它充当“加载”或启动屏幕。
  • @Arjun 这与讨论有点正交,但您永远不应该在您的移动应用程序上放置启动画面。这可能真的会惹恼您的用户。
  • 我还有各种其他的小图像用于图标等。如果是图像大小,这不是很容易重现吗?现在我必须打开应用程序,玩几分钟,然后关闭并打开它以获取错误。
  • @Kurtis:我倾向于同意,但我也看到闪屏有合理用途的情况。例如。启动应用程序时需要很长时间。像我的手机中的愤怒的小鸟那样,最好显示一个启动画面而不是 15 秒的空白黑屏。
  • @JarnoArgillander 够公平的。我完全同意手机游戏是一个完全不同的球场。与其他应用程序相比,您可以在其中获得更多。
【解决方案3】:

最大应用程序 VM 堆大小的典型值为 24 MB。因此,例如,如果您的图像是 10Mpx (3600 x 2400),那么它将分配 3600 x 2400 x 4 = 34'560'000 字节,这是 OutOfMemoryError 的情况。

【讨论】:

  • 我的最大图片只有大约 600kb (png) (1.7m px)。
  • @Arjun:这已经是 RAM 中约 6.8 MB 的位图。一些较旧的设备只有 16 MB 的 VM 堆限制。
  • 好的,让我看看如何减小它的大小。你从哪里得到“4”乘数?
  • 您的代码中是否有需要清理的对象或对对象的引用?如果您不再使用它们,或者暂时不再使用它们,您应该将它们设置为 null,以释放内存。
  • @Arjun:“4”乘数是每个像素的 ARGB 数据。还要确保你没有静态保留任何导致该位图的东西。
【解决方案4】:

在 android 中处理位图时,请确保在使用完位图后回收位图。您可以通过设置 inSampleSize 选项来加载调整大小的位图。更多细节在这里:http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize

【讨论】: