Android在活动生命周期中的内存管理

24

我的问题有点复杂。

我想了解应用程序在启动后如何处理资源(尤其是背景图像、按钮等),当Activity启动后再暂停时的情况。

例如,我启动Activity A,它显示屏幕上的所有图像,占用内存,然后启动另一个Activity B并将A挂起。所有的图像、资源等会发生什么?何时释放它们?我该如何控制它们?是否应该将Activity A从内存中移除并从Activity堆栈中删除?

如果您需要对我的问题进行澄清,请告诉我!

谢谢! 丹尼尔


这个链接会有所帮助:https://queception.com/question.php?question=111 - Stack Overflow
5个回答

21

活动在完成之前不会释放资源。但在大多数情况下,这对你来说不应该是一个问题。在我看来,你不应该在大多数情况下添加自己的资源管理以及使你的代码复杂。

但是如果你真的认为你的应用程序可能会出现内存不足的情况,你应该使用类似于MAT的工具进行检查。内存问题可能是由于内存泄漏而不是内存使用过多引起的。

最终,当你完全确定必须采取一些措施以减少内存使用量时,你可以进行一些内存优化。例如,你可以在onStop()中将占用大量内存的对象(如大型图像)保存到本地存储,并在onStart()中加载它们。我认为使用onPause()/onResume()来实现这个目的是一个不好的主意,因为活动部分或甚至全部可见。

理论上,你甚至可以在onStop()中销毁所有小部件,并在onStart()中恢复它们,但这会使你的应用程序变得太慢。当然,在这种情况下,状态保存必须由你自己实现。

完成活动可能看起来是一个不错的主意,但我认为这不是。首先它会使你的工作变得更慢。其次,你必须自己管理活动堆栈和活动状态。例如,Activity A启动Activity B。那么,当用户按下返回按钮时,Activity B必须知道该做什么。当用户按下返回按钮时,你应该启动Activity A并恢复它的状态。但是如果用户终止了这个应用程序。在这种情况下,你必须使用默认状态初始化Activity A。因此,你必须实现许多额外的逻辑。

最后,我再重复一遍主要观点:如果你不完全确定必须优化内存使用,请不要这样做!


该框架将释放当前活动无法访问的内存。这意味着所有对象、图像等都将被卸载,即使您有对它们的引用,但它们当前未显示(假设您从资源中加载了它们)。只需正确实现onCreate()、onResume()、onPause()、onSaveInstanceState()和onRestoreInstanceState(),您就可以完成设置。自己管理Android框架的内存将会减慢速度并增加错误的风险。 - Szabolcs Berecz
我刚刚浏览了ImageView的源代码,并不认为当活动停止时它会卸载它的可绘制对象。我也不认为TextView会卸载它的文本。而且,实现你提到的方法意味着要进行自己的内存管理。如果你使用模型或者GUI的部分来实现,这并不重要。 - Michael

10

好的,我们有以下情况:

A > onCreate
A > onStart
A > onResume
A > Use up a load of memory (A could even use up too much and crash)
A > Launch activity B
B > onCreate
A > onPause
B > onStart
A > onStop
B > onResume
B > Use up a load of memory 
如果B使用了足够多的内存,那么Android系统将会杀死活动A(您会注意到A的onPause和onStop方法已经被调用,因此它已经有机会保存其状态)。
如果您按下返回按钮,则Android系统将重新启动活动A(如果它聪明的话,应该记住它的上一个状态),因此对于用户而言,看起来就好像什么都没有发生过。
更清晰地说,如果您启动B并完成A,则B基本上只是替换了活动堆栈中的A,并且在B中按下返回按钮只会退出您的应用程序,而不会返回到活动A。
另一方面,如果您启动B而未完成A,则在B中按下返回按钮将带您返回A。虽然活动A在后台运行时可能会被销毁以回收内存,但Android会根据需要在用户通过活动堆栈导航时重新创建它。
此外,如果您有多个对象的内存缓存(例如位图/可绘制对象),请使用SoftReference来支持您的集合,以便GC可以在内存不足时清除它们。

3
你应该设计你的应用程序,使其内存使用低,但是可以依靠框架在内存管理方面尽力而为。因此,在明显你的应用程序占用过多内存的情况下,不要过于努力地删除未使用的内容。
当可用内存降低时,框架将停止并删除与当前任务无关的活动和服务。如果你的应用程序占用了更多的内存,框架将停止后台中的活动。然后是与你的应用程序相关的服务,最后完成的是当前活动。
当框架停止一个活动时,它会保留活动堆栈、用于启动活动的意图以及由onSaveInstanceState()返回的捆绑包的记录,以便可以重新创建活动的最后已知状态。此外,当资源未被使用时,框架可以卸载未使用的资源(可绘制等),并在需要时重新加载它们。

2
在回答您的问题之前,我有一些事实需要讨论。
1. 根据Activity的生命周期,如果我们调用了finish(),则会调用onStop(),最终调用onDestroy(),这使该Activity符合垃圾收集条件,并从Android的Activity堆栈中删除。
2. Android为Activity设计和显示在屏幕上维护Drawable缓存。因此,如果您在onCreate()中禁用了Drawable缓存,则会影响性能。
因此,最佳做法是在onCreate中禁用drawable缓存,如下所示:
 LinearLayout v = (LinearLayout) findViewById(R.id.mainLayout);
        v.setDrawingCacheEnabled(false);

onPause() 中调用 finish(); 方法。


0

在编写Java代码时,您对内存的控制很少。对于大多数情况来说这是一件好事。实际上,大多数应用程序不需要担心内存。

回答您的问题,当Activity A被挂起时,所有对象仍将保留在内存中。当VM需要资源时会启动GC。


我知道在Java中我有很少的控制权,尽管我可以控制它(例如,每次恢复活动时加载位图并在每次暂停时卸载它,否则会出现内存异常)。我的问题是关于资源,例如在xml中定义的背景,如果它们在活动暂停时被卸载。如果我想要节省内存,是否应该从活动堆栈中删除活动。操作系统对内存的内部优化是什么。 - Danail
1
在我看来,我会怀疑平台会为您进行这样的优化。一旦加载所有活动所需的资源都将在内存中(当然,直到它们被垃圾回收)。 - dongshengcn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接