Android内存使用情况和内存中的对象未在1.6和2.1中发布

hoo*_*d82 1 android memory-management out-of-memory

我正在检查我的应用程序内存泄漏/使用情况,并且遇到了一些奇怪的东西,到目前为止我在Android 1.6和2.1中只看到过.在应用程序中点击一下后,我为我的应用程序运行"adb shell dumpsys meminfo",我看到以下内容:

DUMP OF SERVICE meminfo:
Applications Memory Usage (kB):
Uptime: 34639912 Realtime: 153524709

** MEMINFO in pid 5778 [com.app.myapp] **
                    native   dalvik    other    total
            size:    14336     4679      N/A    19015
       allocated:    13971     4139      N/A    18110
            free:      280      540      N/A      820
           (Pss):     2986     4181    13491    20658
  (shared dirty):      972     3948      620     5540
    (priv dirty):     2876     3224    10976    17076

 Objects
           Views:      545        ViewRoots:        4
     AppContexts:       32       Activities:       31
          Assets:        2    AssetManagers:        2
   Local Binders:       43    Proxy Binders:       79
Death Recipients:        2
 OpenSSL Sockets:        1

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

 Asset Allocations
    zip:/data/app/com.app.myapp.apk:/resources.arsc: 119K
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,没有任何东西被解除分配/ GC,活动堆积,AppContexts等等,直到应用程序崩溃与OutOfMemoryError.这不会发生在2.2+上.

有人能告诉我为什么会这样吗?我有一种感觉它或者是简单的东西,或者它只是我的应用程序的奇怪东西,但我不知道为什么会发生这种情况.

仅供参考,我在1.6和2.1仿真器中以及我的G1运行1.6中重现了这一点.用户最近的崩溃报告也显示了这一点,他们在Droid Eris上运行2.1.如果需要更多细节/代码来帮助我,请告诉我.

## UPDATE ##

感谢momo的信息,我能够找到一些内存泄漏问题,这大大减少了将在meminfo的Objects列表中显示的Activities/AppContexts的数量.

现在这个数字已经下降到了我的应用程序中的实际活动数量,因此在旧版本的Android上,它会显示应用程序正在消耗的对象总数.在较新的版本上它不会,但这可能只是我的测试设备上的情况.

mom*_*omo 9

为了清楚地了解为什么要保持活动,我通常使用MAT,然后从被卡住的Activity中查看GC根路径.

我创建了一个简单的项目,它加载简单的TestActivity以说明该过程.以下是它的代码:


package com.so;

import android.app.Activity;
import android.os.Bundle;

public class TestActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

Run Code Online (Sandbox Code Playgroud)

以下是步骤:

  • 通过DDMS"转储HPROF文件"功能将hprof转储到正在运行的进程上
  • 假设你安装了MAT,这应该会调出MAT屏幕
  • 现在根据您的活动包过滤,对于上面的示例,它是com.so. 此过程的屏幕截图如下:

MAT直方图屏幕

  • 现在您想看看它是否有明确的GC路径.您可以通过右键单击"活动"并显示所有引用,如下所示:

显示所有参考

您应该看到您的Activity由com.android.internal.policy.impl.PhoneWindow $ DecorView保留,而不是其他人.如果是这种情况,您就可以了,GC最终将回收此活动.

现在我将更改我的类以包含一个将保存其自己的实例的静态变量:


package com.so;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;

public class TestActivity extends Activity {
    static ArrayList memoryLeakList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // create a deliberate static list to cause the leak
        TestActivity.memoryLeakList = new ArrayList();
        TestActivity.memoryLeakList.add(this);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我用相同的步骤运行代码hprof,我现在得到的活动的引用由ArrayList保存,而不是com.android.internal.policy.impl.PhoneWindow $ DecorView表示有可能发生泄漏我不清理阵列

ArrayList导致的内存泄漏

现在,您不必为每个Activity执行此操作,我只需简单地运行应用程序然后转储HPROF.然后,您将再次按包筛选以获取应用程序的快照.在初始直方图中,在DDMS中点击GC按钮并从那里开始调查后,您应该怀疑任何具有多个实例的活动.

还有一点需要注意,在我的2.1手机上,我无法通过DDMS获得HPROF,所以我按照以下步骤通过模拟器完成了:

  • 转到./adb shell
    • 输入ps以获取应用进程的pid
    • 输入kill -10,你应该在你的logcat中看到它正在将内存转储到/ data/misc
    • 如果您获得了权限被拒绝,请确保通过执行chmod 777 data/misc来读取/写入该文件夹
  • 使用Eclipse中的DDMS File Explorer或pull命令拉出生成的hprof
  • 由于hprof是基于dalvik的,为了将其与内存分析工具一起使用,您需要首先通过Android SDK安装的tools目录中的hprof-conv进行转换.

    Run ./hprof-conv [source dump] [target dump]