【问题标题】:Resume time memory optimization恢复时间内存优化
【发布时间】:2013-07-07 07:35:55
【问题描述】:

我是根据一些事实写这个问题的。 比如我们不能明确控制垃圾收集器(GC)。所以也没有办法检查 GC 何时会从我暂停的活动中获取内存。

我正在谈论的测试用例: 我在 onCreate 方法中分配了许多对象,包括 HashMaps 和 ArrayLists。 其中一些用于存储位图的引用。 现在用户通过按主页按钮暂停活动。 比我长时间执行其他任务后忘记恢复相同的任务。 现在,当我回到暂停的活动时。

问题是:1) 有没有机会假装或假设在这种情况下,内存 GC 将首先获取什么?

2) gc 是仅获取整个活动还是仅获取部分空闲和空对象?

3) 假设在 5 到 6 小时后用户恢复活动,我怎么知道有些对象被垃圾回收了。

4) 如果某些对象被垃圾回收,那么在 onResume 中检查它们是否为空就足以进一步访问它们。

5) 在这种情况下如何处理空指针访问。

我很想听听每一个建议。 谢谢你的关注。 编码愉快。

【问题讨论】:

    标签: android android-activity android-lifecycle android-memory


    【解决方案1】:

    如果您的活动已在后台运行了 5 或 6 个小时,则几乎可以肯定 Android 已经杀死了托管进程。当用户返回您的应用程序时,Android 将为该应用程序创建一个新进程,然后重新实例化一个活动。通常,在 5 或 6 小时后,Android 将丢弃所有保存的状态,并从头重新启动您的应用(除非您为根 Activity(启动 Activity)特别指定了android:alwaysRetainTaskState="true"

    如果您在 5 或 6 小时后返回“暂停”活动,并且应用程序的进程已被终止并重新创建,则 onCreate() 将在 onResume() 之前再次调用您的活动。

    GC 与此无关。如果您的活动实例是活动的,GC 将不会回收它所引用的任何对象。如果您看到变量被设置为 null,这是因为 Android 已经杀死了您的进程,然后又创建了一个新进程。

    【讨论】:

    • 好吧,AFAIK android 只会在内存不足的情况下杀死您的活动或(应用程序)并且基于频繁使用,我真的怀疑它是否会根据时间杀死任何暂停的活动。我真的很感兴趣你的答案是因为如果它杀死了一个进程,就必须释放它分配的所有内存引用。图片中的 GC 就是这样。
    • 其实Android可以随时杀死你的进程(如果它在后台的话)。在较新的设备(Android 4.0 及更高版本)上,尤其是在 HTC 设备上,“进程终止”更具侵略性。在大多数情况下,如果您的应用程序在后台运行超过几分钟,它很可能会被杀死。查看 here 了解 Android 在暂停 30 分钟后清除任务的说明。
    • 关于您对 GC 和进程终止的评论,您错了:当 Android 终止您的进程时,它只会终止操作系统进程。繁荣。走了。它不会在任何组件上调用onDestroy(),它根本不会调用GC,因为当它杀死进程时,VM(虚拟机)也会被杀死,因此它不需要清理任何资源。 Android 经常这样做,你需要确保你的代码可以处理它。
    【解决方案2】:

    据我所知,GC 会运行 VM 中的所有对象,如果没有对对象的引用,则会将其删除。 Android Activity 有点不同,它有自己的lifecycle
    当 Androids 需要更多 RAM 用于其他应用程序(活动)时,然后在您的活动中调用 onSaveInstanceState (Bundle outState)。在这个地方你应该把你需要的一切保存到Bundle当用户回到你的活动时你可以在onRestoreInstanceState(Bundle savedInstanceState)中恢复这些对象。

    编辑:以我的应用为例:

    public class Window {
        public Window(Bundle bundle) {
            maximized = bundle.getBoolean("maximized", maximized);
            displayed = bundle.getBoolean("displayed", displayed);
            minimized = bundle.getBoolean("minimized", minimized);
            resizable = bundle.getBoolean("resizable", resizable);
            orientation = bundle.getInt("orientation");
        }
        public Bundle bundle() {
            Bundle bundle = new Bundle();
            bundle.putBoolean("maximized", maximized);
            bundle.putBoolean("displayed", displayed);
            bundle.putBoolean("minimized", minimized);
            bundle.putBoolean("resizable", resizable);
            bundle.putInt("orientation", orientation);
            return bundle;
        }
    }
    

    还有 MainActivity:

    public class MainActivity extends Activity {
        ArrayList<Window> windows;
        [...]
    
        @Override
        public void onSaveInstanceState(Bundle savedInstanceState) {
            super.onSaveInstanceState(savedInstanceState);
            Bundle[] windowsBundle = new Bundle[windows.size()];
            for(int i=0; i<windowsBundle.length; i++){
                windowsBundle[i] = windows.get(i).bundle();
            }
            savedInstanceState.putParcelableArray("windows", windowsBundle);
        }
        @Override
        public void onRestoreInstanceState(Bundle savedInstanceState){
            super.onRestoreInstanceState(savedInstanceState);
            Parcelable[] windowsParcels = savedInstanceState.getParcelableArray("windows");
            Bundle[] windowsBundle = (Bundle[]) Arrays.copyOf(windowsParcels, windowsParcels.length, Bundle[].class);
            windowsParcels = null;
            for(int i=0; i<windowsBundle.length; i++){
                windows.add(new Window(windowsBundle[i]));
            }
        }
    }
    

    【讨论】:

    • 你的意思是我应该在每个活动上都这样做,即使我在我的应用程序中导航。
    • 是的。将每个对象保存到捆绑包中似乎很累人,但有人认为这是保存活动数据的最佳方式。
    猜你喜欢
    • 2020-01-19
    • 2021-11-07
    • 2017-02-21
    • 2018-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多