【问题标题】:Memory and Activities :: OutOfMemory记忆和活动 :: OutOfMemory
【发布时间】:2012-01-26 17:41:13
【问题描述】:

设置:

我有这个应用程序,它在线性路径中有 4 个活动,非常简单的导航: A -> B -> C -> D

所有活动共享相同的背景图像,并且都有几个常规按钮,一个文本视图或一个编辑文本。所有这些都在单独的视图 xml 文件中定义。

背景是渐变的,有点重。大约 3 兆作为未压缩的位图。

应用程序什么也不做,其中唯一的逻辑是启动活动并在单击按钮时关闭它们

我尝试使用 MAT 查找内存泄漏,但找不到任何东西。我的应用程序中最大的保留大小是 656(ko?),应用程序的总保留大小是 1520(ko?),我找不到任何会重复的对象。 顺便说一句,这与显示 27300(ko?) 已分配的 dumpsys 完全矛盾

问题:

  1. 当我向上导航时,我发现内存使用量增加了相当于背景大小。
  2. 当我向下导航、使用返回按钮或完成命令关闭活动时,应用程序的内存使用量不会减少。
  3. 如果我从 A 转到 D 然后回到 B 并旋转屏幕,应用程序强制关闭并出现 OutOfMemory 异常。

问题:

更新:我想真正的问题是为什么我有一个巨大的内存泄漏(一次 5 兆),冻结时应用程序大小为 27 兆,而我在 MAT 中看不到它?

  1. 为什么 Android 会多次解压缩同一背景,每个活动一次?似乎效率低下。
  2. 是否可以通过使用主题来解决这个问题,或者我会看到相同的“按活动分配 1 个背景”的怪异现象?
  3. 为什么活动关闭后没有回收?
  4. 为什么 MAT 和 dumpsys 显示不同的数字?

线索

在同一时间我有: 转储系统内存信息:

Applications Memory Usage (kB):
Uptime: 74006853 Realtime: 110962243

** MEMINFO in pid 22683 [com.kayenko.sosadresse] **
                    native   dalvik    other    total
            size:    20820     5767      N/A    26587
       allocated:    18751     2901      N/A    21652
            free:      312     2866      N/A     3178
           (Pss):     1357      201    16782    18340
  (shared dirty):     2264     1804     5456     9524
    (priv dirty):     1280      116    16032    17428

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

 SQL
               heap:        0         MEMORY_USED:        0
 PAGECACHE_OVERFLOW:        0         MALLOC_SIZE:        0

还有这棵支配树:

感谢任何知道我要寻找什么线索的人。

【问题讨论】:

    标签: android memory themes


    【解决方案1】:

    内存是 Android 中一个非常棘手的主题。

    每个应用都会根据设备获得堆内存限制。这个堆内存是dalvik内存加上本机内存,你可以在dumpsys meminfo结果中看到它的总列。 dalvik 内存处理除了位图之外的所有内容,这些位图分配在本机内存中(对于 Honeycomb 之前的 Android 版本是这样)。

    话虽如此,我只能回答你的一些问题:

    1. 据我所知,Android 将始终为位图分配内存,即使它们是相同的。因此,在您的情况下,每个活动都会为您的背景分配内存。

    2. 我不知道使用主题是否更好,您必须尝试一下。

    3. 一方面,当设备有足够的内存来处理下一个活动时,活动不会被回收。当您按下后退按钮时,每个活动都会被推到一堆,从那里恢复。如果 Android 需要更多内存,它会从释放内存的堆中删除一个活动(回到第一个问题,也许这就是不共享内存的原因)。另一方面,您可以设置活动launchMode 来改变这种行为(看看here)。

    4. 我认为 MAT 不显示本机内存数据。使用dumpsys meminfo 的本机列查看您为位图分配了多少内存。

    我自己也很难处理 OutOfMemory 问题。现在我有了一个更清晰的想法 它是如何工作的,我能够在不耗尽内存的情况下处理大文件。我强烈推荐这两个对我有很大帮助的资源:

    祝你好运!

    【讨论】:

    • 谢谢哈维,这非常有用。我已经查看了您给我的链接,但不幸的是没有任何帮助。我不知道启动模式,必须承认我对它应该做什么一无所知。我想我必须对其进行测试,因为文档和往常一样“缺乏”:)
    • 我会把你的答案标记为答案,因为你实际上给了我 4 个答案中的 3 个:D
    【解决方案2】:

    经过数小时的调查和哈维的帮助,结果如下:

    问。为什么Android会多次解压缩相同的背景,每次活动一次?似乎效率低下。

    A.尽管由于我们使用的是内存很少的移动设备,因此通过某种方式要求在活动之间共享位图似乎是合乎逻辑的,但这在 Android 中似乎并不存在。每次在不同的活动中使用位图时,它都会解压缩到本机内存。

    问。是否可以通过使用主题来克服这个问题,或者我会看到相同的“按活动分配一个位图”的怪异现象?

    经过实验,使用主题消耗的内存与在布局的 xml 中显式设置位图所使用的内存量完全没有区别。这对我来说很奇怪,因为样式是将属性分组到同一个地方。

    问。为什么活动关闭后没有回收?

    A.好吧,我不确定,但我发现这几乎只在调试时给了我 OOM 错误。从设备启动应用程序时,它几乎从未发生过。调试过程中出现故障?在您花 5 小时测试无数事物之前先尝试一下。

    问。为什么 MAT 和 dumpsys 显示不同的数字?

    A. Xavi 的答案是正确的,dumpsys meminfo 显示所有分配的内存(本机 + dalvik),而 MAT 仅显示 Dalvik 一个。由于位图像素是在本机内存中分配的,因此 MAT 不会看到它。这只是在 Android 3.0 之前,他们改变了分配方案并使位图的像素数据适合 Dalvik。

    问。我是如何解决我的问题的

    A.首先,在不调试时这可能不是问题。其次,为了安全起见,我将渐变 png 替换为具有径向渐变的形状并使用了

    getWindow().setFormat(PixelFormat.RGBA_8888);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_DITHER);
    

    在我的活动的 oncreate 中尽量避免条带化。我仍然会在某些设备上使用条带,但我宁愿有条带而不是 FC

    【讨论】:

      【解决方案3】:

      您需要在销毁活动时明确回收用作背景的位图。代码将是这样的:

      @Override
      protected void onDestroy () {
          Drawable drawable = getView().getBackground();
          if (drawable instanceof BitmapDrawable) {
              ((BitmapDrawable)drawable).getBitmap().recycle();
          }
          drawable.setCallback(null);
          getView().setBackgroundDrawable(null);
          super.onDestroy();
      }
      

      也许您需要为嵌套视图递归地释放资源,但这取决于您的布局结构。这是一般情况

      【讨论】:

      • 感谢您的意见,遗憾的是它根本没有帮助。根据您的代码,我的小部件都没有 bitmapdrawables,我还尝试了此页面中的代码:alonsoruibal.com/bitmap-size-exceeds-vm-budget,然后将两者混合以尽可能激进但无济于事。
      • 我不同意。一旦不再引用位图,Dalvik 将自动回收位图。没必要手动做,recycle()方法是存在的,所以你可以加快这个过程,提前回收内存。
      猜你喜欢
      • 2018-04-30
      • 1970-01-01
      • 2013-05-12
      • 2011-04-25
      • 2012-08-21
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多