【问题标题】:Multiple Instance of Activity Out of memory多个Activity实例内存不足
【发布时间】:2017-08-25 15:26:56
【问题描述】:

我有一个内存不足的问题。

我有一套跨应用程序的活动和一个类。

我在每个活动的清单中将launchMode 设置为SingleTop,并将noHistory 设置为true。 我也设置了android: largeHeap = "true"

我称之为 A、B、C、D、E 的一项主要活动和五项其他活动

A、B、C 总是在 HEAP 中显示单个实例,但 D 和 E 每次新 Intent 及其 startActivity 都会增加实例数

C 使用 D 和 E 中也使用的相同对象(listview、hashmap、simpleAdapter)

发生这种情况:

主启动,然后启动C,C调用D和D调用E返回C。C总是有一个实例,而D和E每次占用1MB来指示它们的实例,最终导致Oom叠加 174Mb可用为我的应用程序。

对于我运行此代码的所有活动,例如从 activityB、startC、activityC。

Intent activityC = new Intent (getBaseContext, activityC.class); // Try too getApplicationContext, activityC.this but instances remain anyway.

activityC.setFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); // I try too SINGLE_TOP, NEW_TASK, CLEAR_TASK same result

Finish (); // I also tried to call finish () after startActivity () with the same result
startActivity (activityC);

这一切都一文不值。

我还使用freeMemory() 函数调用每个活动的onDestroy(),但不管有没有变化

Public void freeMemory () {

System.runFinalization ();
Runtime.getRuntime (). Gc ();
System.gc ();

}

我已经尝试实现onNewIntent,但我从来没有得到它。

在 D 和 E onDestroy 中,我尝试将在 onCreate() 中创建的所有对象(私有)设置为 null,但未成功。

目前我正在尝试使用华硕和 Android 5.02 平板电脑。

不要使用 Handler、Timer 或 AsyncTask。

我做了多少努力(我真的尝试了很多)A、B、C 总是在 HEAP 中显示单个实例,而 D 和 E

我还创建了一个演示来尝试解决问题,但我没有得到结果。在 SINGLE_TOP 演示中,您可以按预期工作,并为每个活动保留一个实例,超过其重复次数。

什么可以保留新实例?

清单:

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.INTERNET" />

<application
    android:name=".TEST"
    android:allowBackup="true"
    android:hardwareAccelerated="false"
    android:icon="@drawable/logo"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".ActivityA"
        android:hardwareAccelerated="false"
        android:label="@string/app_name"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name=".ActivityE"
        android:enabled="true"
        android:hardwareAccelerated="false"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:noHistory="true"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme" />

    <activity
        android:name=".ActivityD"
        android:hardwareAccelerated="true"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:noHistory="true"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.NoActionBar" />

    <activity
        android:name=".ActivityC"
        android:hardwareAccelerated="true"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:noHistory="true"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.NoActionBar" />

    <activity
        android:name=".ActivityB"
        android:hardwareAccelerated="true"
        android:launchMode="singleTop"
        android:noHistory="true"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.NoActionBar" />


    <activity android:name=".TempActivity"
        android:launchMode="singleTop"
        android:noHistory="true"
        />
</application>

</manifest>

我注意到当你从一个活动切换到另一个 logcat 时告诉我: 08-26 08:22:33.607 905-5207 /? W / ActivityManager: startActivity 从完成 ActivityRecord {6d2eb11 u0 danielezampieri.TEST / .ActivityC t472 f} 中调用;强制 Intent.FLAG_ACTIVITY_NEW_TASK 用于: Intent {flg = 0x24020000 cmp = danielezampieri.TEST / .ActivityD} 因为?这是什么意思?难道是因为ActivityC生成了多个实例?

但是我在startactivity之后注释了finish()方法,只有上面提到的activity显示了多个实例。

更新!! 我把注意力集中在产生问题的地方。无论如何感谢您的建议。 在activityC(显示多个实例并占用无用内存的那个)中,我有两个扩展Dialog的类,在活动的oncreate中创建它们

newmydialog1 = New mydialog1 (this)
newmydialog1 = New mydialog2 (this)

然后我打电话

newmydialog1.show

在 mydialog1 中有一个按钮正在运行

newmydialog2.show

如果我运行 mydialog2,除非我按下运行 mydialog2 的按钮,否则我不会创建 activityC 的多个实例,这里是 activityC 上的内存泄漏,它相信每个创建的实例。 我尝试调用 newmydialog2.cancel/dismiss,然后在 mydialog1 的 cancel () 之前将 newmydialog2 设置为 null,但没有。 我还能做什么?

【问题讨论】:

  • 请发布您的清单
  • 您的 D 和 E 实例没有消失的原因也可能是因为某些东西持有对它们的引用。要检查这一点,请运行您的应用程序,从 C 到 D 再到 E 并返回几次。然后进行堆转储以查看堆中有多少个 C、D 和 E 实例。同时执行adb shell dumpsys activity activities 并查看任务中的活动列表。
  • 我建议实施 LeakCanary 来帮助追踪您的内存泄漏:github.com/square/leakcanary。此外,如果您运行“lint”Gradle 任务,您是否会收到将 Context 值存储在成员/静态变量中的任何警告?我的猜测是 Context 变量在某处被存储为硬引用,这导致活动没有被垃圾收集。
  • 另外,您的应用是原生应用还是将 HTML 内容加载到 WebView 中?如果我没记错的话,Marshmallow 之前有一个缺陷,任何使用 WebView 的 Activity 都无法正确收集垃圾。
  • 不,不是原生应用 (JNI) 且不使用 WebView

标签: android android-intent memory-leaks


【解决方案1】:

如果 C & D & E 共享相同的对象,为什么不让 ActivityC 有一个 ViewFlipper 以在 C & D & E 的内容之间“翻转”,如果你有很多图像尝试缩放它们关闭或重新使用它们,而不是每次都创建它们......如果您担心翻转视图时滞后,请尝试使用 Async-task 来,例如,在创建 Activity 时创建 D 的内容......也使用RecyclerViews 可能会有所帮助,而不是 ListViews..... 我希望我能帮助你 :)

【讨论】:

【解决方案2】:

问题解决方案

mydialog2 的新实例必须在 mydialog1 类中并且在 newmydialog2.show() 之前。

【讨论】:

    猜你喜欢
    • 2018-03-29
    • 1970-01-01
    • 2019-09-29
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多