我注意到我的应用程序正在泄漏内存。这可以在DDMS和我看到 设法获得OutOfMemoryError。
我找到了泄漏源。其中一个活动有一个在后台运行的线程。该线程在onDestroy()
中停止。它完成了运行,因为它可以在DDMS中看到。
现在,如果线程被启动,则发生泄漏,Activity被销毁后不会被垃圾收集,因为它被线程引用。 如果线程根本没有启动,一切都还可以。
以下是证明这一点的简单示例:
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
volatile boolean finished = false;
byte[] memoryEater = new byte[4 * 1024 * 1024];
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (!finished) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(getClass().getName(), "Thread finished");
}
});
@Override
protected void onDestroy() {
super.onDestroy();
finished = true;
}
public void startActivity(View view) {
startActivity(new Intent(this, MainActivity.class));
}
public void startThread(View view) {
thread.start();
}
}
添加一个用于启动新活动的按钮和一个用于启动线程的按钮。开始新的活动。返回后,只有在线程尚未启动时才会清理内存。
这种行为的原因是什么?
答案 0 :(得分:13)
我刚刚发现了同样的问题。
托马斯,你走在正确的轨道上。 DDMS中没有错误,程序中没有内存泄漏。真正的问题是你是在DEBUG模式下运行你的程序(在Eclipse下)。不知何故,当Android在DEBUG模式下运行时,即使在退出run()方法之后,线程也不会被垃圾回收。我想这可能是Android需要坚持使用线程才能使某些调试功能正常工作。
但是如果你在RUN模式下运行应用程序(仍然在Eclipse下),就会发生Thread垃圾收集。线程将被完全释放,您的活动将被完全释放。
答案 1 :(得分:4)
我一直在调查,我发现的确是令人惊讶的。似乎没有真正的内存泄漏。仅当app在DDMS中处于调试模式时才会发生。
DDMS似乎以某种方式保留对那些成品胎面的参考,从而阻止它们被GC编辑。当我断开手机并再次连接时,我可以看到所有“泄露”的资源都已被释放。
它看起来像是DDMS中的一个错误。
答案 2 :(得分:2)
线程使用的匿名runnable类将引用该活动('this')。由于活动引用了线程,并且线程中的runnable引用了该活动,因此GC将永远不会收集它们中的任何一个。
尝试做更像这样的事情:
private static RunnableClass implements Runnable
{
@Override
public void run() {
while (!finished) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.d(getClass().getName(), "Thread finished");
}
});
Thread thread = new Thread(new RunnableClass());
答案 3 :(得分:0)
当按下“后退”或发送任何其他意图将其从堆栈顶部移除时,不会销毁活动。 在您的Android操作系统内存不足之前,我认为您的覆盖onDestroy()方法不会被调用。 从documentation可以提取:
如以下关于活动生命周期的部分所述, Android系统为您管理活动的生命,所以您可以 不需要完成自己的活动。调用这些方法可以 对预期的用户体验产生不利影响,只应使用 当你绝对不希望用户返回此实例时 活动。
通常,每个Activity实例在初始创建后都会在内存中存放,并且会经历onStart()...onStop()
循环而不会被破坏。实施onStop()
并在其中调用finish()
MainActivity
,并释放线程并进行垃圾收集。
更新:上述陈述不属实。根据问题中提供的代码,没有理由不对GC进行GC编辑。