在 onPause 而不是 onDestroy 中释放资源
Release resources in onPause instead of onDestroy
这是关于 POST-honeycomb(即 Android 3.0+),下面的引用来自 https://developer.android.com/reference/android/app/Activity.html
根据生命周期,onStop 和 onDestroy 是可杀死的,这意味着:
Note the "Killable" column in the above table -- for those methods
that are marked as being killable, after that method returns the
process hosting the activity may be killed by the system at any time
without another line of its code being executed
换句话说,保证 调用 onStop(以及在此事件之前发生的其他事件),但目前方法 returns,进程可能会终止,因此 不保证 调用 onDestroy。
另一引述:
For those methods that are not marked as being killable, the
activity's process will not be killed by the system starting from the
time the method is called and continuing after it returns.
其次是
Thus an activity is in the killable state, for example, between after
onPause() to the start of onResume().
但是这不对应上面说的,除非这只对应预蜂巢。 POST-honeycomb 不是这样的,对吧?所以基本上,onPause和onStop都保证会被调用。
假设我只在 onDestroy 中释放一个资源,那么这可能会导致泄漏,因为 onDestroy 可能不会被调用,对吧?
但是,当进程被android自身杀死时,除了之外,是否会出现这种情况(即不调用onDestroy)?有没有其他场景导致onDestroy不被调用,从而泄露资源.
当Android杀死进程时资源将被破坏并且不会发生泄漏是真的吗(即使我们没有明确释放资源?)。
请详细说明(1)(2)(3)(4)(5)是否正确。
首先让我们了解一下您引用的文档是怎么回事。
以下命令显示 AOSP 中 Activity.java
文件的 git blame
输出:
$ cd $AOSP/frameworks/base
$ git blame ./core/java/android/app/Activity.java
输出的相关部分:
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 363) * <p>Note the "Killable" column in the above table -- for those methods that
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 364) * are marked as being killable, after that method returns the process hosting the
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 365) * activity may killed by the system <em>at any time</em> without another line
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 366) * of its code being executed. Because of this, you should use the
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 367) * {@link #onPause} method to write any persistent data (such as user edits)
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 368) * to storage. In addition, the method
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 369) * {@link #onSaveInstanceState(Bundle)} is called before placing the activity
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 370) * in such a background state, allowing you to save away any dynamic instance
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 371) * state in your activity into the given Bundle, to be later received in
550116576 (RoboErik 2014-07-09 15:05:53 -0700 372) * {@link #onCreate} if the activity needs to be re-created.
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 373) * See the <a href="#ProcessLifecycle">Process Lifecycle</a>
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 374) * section for more information on how the lifecycle of a process is tied
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 375) * to the activities it is hosting. Note that it is important to save
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 376) * persistent data in {@link #onPause} instead of {@link #onSaveInstanceState}
5c40f3fcc (Daisuke Miyakawa 2011-02-15 13:24:36 -0800 377) * because the latter is not part of the lifecycle callbacks, so will not
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 378) * be called in every situation as described in its documentation.</p>
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 379) *
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 380) * <p class="note">Be aware that these semantics will change slightly between
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 381) * applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 382) * vs. those targeting prior platforms. Starting with Honeycomb, an application
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 383) * is not in the killable state until its {@link #onStop} has returned. This
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 384) * impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 385) * safely called after {@link #onPause()} and allows and application to safely
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 386) * wait until {@link #onStop()} to save persistent state.</p>
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 387) *
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 388) * <p>For those methods that are not marked as being killable, the activity's
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 389) * process will not be killed by the system starting from the time the method
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 390) * is called and continuing after it returns. Thus an activity is in the killable
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 391) * state, for example, between after <code>onPause()</code> to the start of
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 392) * <code>onResume()</code>.</p>
请注意,讨论 post-Honeycomb 行为的段落是由 Dianne Hackborn 于 2010-12-07 添加的,而封闭段落可追溯到 2009-03-03。
它告诉我们的是 Dianne 添加了新段落而没有更新 javadoc 的其余部分,因此矛盾。不幸的是,这在 Android.
中并不罕见
针对您的问题:
1) 在 post-Honeycomb 版本的 Android 上 onResume()
和 onStop()
都保证被调用(正如 Dianne Hackborn 在她对 Activity 的 javadoc).
2) 在 Honeycomb 之前只有 onPause()
保证被调用(如 Activity 的 javadoc 的早期版本所述)
3,4,5) onDestroy()
只有在托管整个应用程序的进程被终止时才会被调用。当进程被杀死时,分配给它的所有资源都被释放,因此在这种情况下不存在内存泄漏的风险。
重要说明:由于在onDestroy()
中释放资源不会导致内存泄漏,将所有"releasing"代码放在一起看起来是个好主意那里。但是,它很少是最佳方法。为什么?阅读下文。
当 Activity
进入后台时,它会停止,但不会被销毁(通常)。 Activity
可以在这个 "stopped" 状态保持相当长的时间,如果用户 returns 到应用程序将再次启动。如果您在 onDestroy()
中释放资源,当 Activity
进入后台时默认情况下不会调用该资源,Activity
将在停止状态下保留这些资源,从而导致更多的资源在后台状态下被您的应用消耗。
当Android 内存不足时,它会开始终止进程以释放它们消耗的内存。选择要终止的进程时要考虑的最重要的考虑因素之一是它们的资源消耗。因此,如果您的应用程序在后台停止状态下持有资源,它将有更高的机会被 Android.
杀死。
此外,我们开发人员必须确保为我们的用户制作最好的应用程序。在后台消耗非最小用户 phone 资源和电池的应用程序不是好的应用程序。用户会知道的!
因此,我强烈建议在onStop()
方法中释放所有资源。我通常根本不会覆盖 Activities
和 Fragments
中的 onDestroy()
方法。
推论: 正如@Juan 在他的评论中指出的那样,上述重要说明有一个同样重要但不那么明显的推论:onStart()
应该是分配资源的唯一方法。无论您对 "resources" 的定义是什么,onCreate()
和 onResume()
都不应该分配这些资源。
我认为 Vasily 提供了很好的答案。仍然缺少一个与
相关的小而重要的点
- Is it true that when Android kills the process that the resources will be destroyed and no leak can occur (even when we did not explicitly released the resource?).
答案取决于你到底害怕什么。正如 Vasily 所指出的 Android(基于 Linux)是一个现代安全 OS,它保证当进程被杀死时,所有的内存都将被释放,此外还有所有打开的文件、网络连接等也会妥善关闭。所以不会有通常意义上的资源泄漏。
仍然存在一种可能存在问题的情况。假设您在释放某些资源时执行某些逻辑,即您将放入 C++ 中的析构函数或 Java 中 Closeable.close
的实现中的某些内容。例如,您在内存中有一个缓存,可以延迟写入带有批处理的文件。通常你刷新 onDestroy
中的内存缓存,一切正常。但是当进程被 Android 强行杀死时,onDestroy
可能不会被调用并且您的刷新逻辑不会被执行,因此您可能会丢失一些数据 and/or 在您的持久存储中具有无效状态。所以如果你有这样的事情,你应该通过在更可靠的地方执行这样的逻辑来确保一致性:onPause
或 onStop
.
这是关于 POST-honeycomb(即 Android 3.0+),下面的引用来自 https://developer.android.com/reference/android/app/Activity.html
根据生命周期,onStop 和 onDestroy 是可杀死的,这意味着:
Note the "Killable" column in the above table -- for those methods that are marked as being killable, after that method returns the process hosting the activity may be killed by the system at any time without another line of its code being executed
换句话说,保证 调用 onStop(以及在此事件之前发生的其他事件),但目前方法 returns,进程可能会终止,因此 不保证 调用 onDestroy。
另一引述:
For those methods that are not marked as being killable, the activity's process will not be killed by the system starting from the time the method is called and continuing after it returns.
其次是
Thus an activity is in the killable state, for example, between after onPause() to the start of onResume().
但是这不对应上面说的,除非这只对应预蜂巢。 POST-honeycomb 不是这样的,对吧?所以基本上,onPause和onStop都保证会被调用。
假设我只在 onDestroy 中释放一个资源,那么这可能会导致泄漏,因为 onDestroy 可能不会被调用,对吧?
但是,当进程被android自身杀死时,除了之外,是否会出现这种情况(即不调用onDestroy)?有没有其他场景导致onDestroy不被调用,从而泄露资源.
当Android杀死进程时资源将被破坏并且不会发生泄漏是真的吗(即使我们没有明确释放资源?)。
请详细说明(1)(2)(3)(4)(5)是否正确。
首先让我们了解一下您引用的文档是怎么回事。
以下命令显示 AOSP 中 Activity.java
文件的 git blame
输出:
$ cd $AOSP/frameworks/base
$ git blame ./core/java/android/app/Activity.java
输出的相关部分:
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 363) * <p>Note the "Killable" column in the above table -- for those methods that
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 364) * are marked as being killable, after that method returns the process hosting the
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 365) * activity may killed by the system <em>at any time</em> without another line
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 366) * of its code being executed. Because of this, you should use the
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 367) * {@link #onPause} method to write any persistent data (such as user edits)
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 368) * to storage. In addition, the method
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 369) * {@link #onSaveInstanceState(Bundle)} is called before placing the activity
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 370) * in such a background state, allowing you to save away any dynamic instance
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 371) * state in your activity into the given Bundle, to be later received in
550116576 (RoboErik 2014-07-09 15:05:53 -0700 372) * {@link #onCreate} if the activity needs to be re-created.
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 373) * See the <a href="#ProcessLifecycle">Process Lifecycle</a>
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 374) * section for more information on how the lifecycle of a process is tied
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 375) * to the activities it is hosting. Note that it is important to save
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 376) * persistent data in {@link #onPause} instead of {@link #onSaveInstanceState}
5c40f3fcc (Daisuke Miyakawa 2011-02-15 13:24:36 -0800 377) * because the latter is not part of the lifecycle callbacks, so will not
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 378) * be called in every situation as described in its documentation.</p>
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 379) *
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 380) * <p class="note">Be aware that these semantics will change slightly between
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 381) * applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 382) * vs. those targeting prior platforms. Starting with Honeycomb, an application
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 383) * is not in the killable state until its {@link #onStop} has returned. This
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 384) * impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 385) * safely called after {@link #onPause()} and allows and application to safely
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 386) * wait until {@link #onStop()} to save persistent state.</p>
0aae2d4e0 (Dianne Hackborn 2010-12-07 23:51:29 -0800 387) *
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 388) * <p>For those methods that are not marked as being killable, the activity's
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 389) * process will not be killed by the system starting from the time the method
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 390) * is called and continuing after it returns. Thus an activity is in the killable
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 391) * state, for example, between after <code>onPause()</code> to the start of
9066cfe98 (The Android Open Source Project 2009-03-03 19:31:44 -0800 392) * <code>onResume()</code>.</p>
请注意,讨论 post-Honeycomb 行为的段落是由 Dianne Hackborn 于 2010-12-07 添加的,而封闭段落可追溯到 2009-03-03。
它告诉我们的是 Dianne 添加了新段落而没有更新 javadoc 的其余部分,因此矛盾。不幸的是,这在 Android.
中并不罕见针对您的问题:
1) 在 post-Honeycomb 版本的 Android 上 onResume()
和 onStop()
都保证被调用(正如 Dianne Hackborn 在她对 Activity 的 javadoc).
2) 在 Honeycomb 之前只有 onPause()
保证被调用(如 Activity 的 javadoc 的早期版本所述)
3,4,5) onDestroy()
只有在托管整个应用程序的进程被终止时才会被调用。当进程被杀死时,分配给它的所有资源都被释放,因此在这种情况下不存在内存泄漏的风险。
重要说明:由于在onDestroy()
中释放资源不会导致内存泄漏,将所有"releasing"代码放在一起看起来是个好主意那里。但是,它很少是最佳方法。为什么?阅读下文。
当 Activity
进入后台时,它会停止,但不会被销毁(通常)。 Activity
可以在这个 "stopped" 状态保持相当长的时间,如果用户 returns 到应用程序将再次启动。如果您在 onDestroy()
中释放资源,当 Activity
进入后台时默认情况下不会调用该资源,Activity
将在停止状态下保留这些资源,从而导致更多的资源在后台状态下被您的应用消耗。
当Android 内存不足时,它会开始终止进程以释放它们消耗的内存。选择要终止的进程时要考虑的最重要的考虑因素之一是它们的资源消耗。因此,如果您的应用程序在后台停止状态下持有资源,它将有更高的机会被 Android.
杀死。此外,我们开发人员必须确保为我们的用户制作最好的应用程序。在后台消耗非最小用户 phone 资源和电池的应用程序不是好的应用程序。用户会知道的!
因此,我强烈建议在onStop()
方法中释放所有资源。我通常根本不会覆盖 Activities
和 Fragments
中的 onDestroy()
方法。
推论: 正如@Juan 在他的评论中指出的那样,上述重要说明有一个同样重要但不那么明显的推论:onStart()
应该是分配资源的唯一方法。无论您对 "resources" 的定义是什么,onCreate()
和 onResume()
都不应该分配这些资源。
我认为 Vasily 提供了很好的答案。仍然缺少一个与
相关的小而重要的点
- Is it true that when Android kills the process that the resources will be destroyed and no leak can occur (even when we did not explicitly released the resource?).
答案取决于你到底害怕什么。正如 Vasily 所指出的 Android(基于 Linux)是一个现代安全 OS,它保证当进程被杀死时,所有的内存都将被释放,此外还有所有打开的文件、网络连接等也会妥善关闭。所以不会有通常意义上的资源泄漏。
仍然存在一种可能存在问题的情况。假设您在释放某些资源时执行某些逻辑,即您将放入 C++ 中的析构函数或 Java 中 Closeable.close
的实现中的某些内容。例如,您在内存中有一个缓存,可以延迟写入带有批处理的文件。通常你刷新 onDestroy
中的内存缓存,一切正常。但是当进程被 Android 强行杀死时,onDestroy
可能不会被调用并且您的刷新逻辑不会被执行,因此您可能会丢失一些数据 and/or 在您的持久存储中具有无效状态。所以如果你有这样的事情,你应该通过在更可靠的地方执行这样的逻辑来确保一致性:onPause
或 onStop
.