大内存块没有垃圾收集

在寻找我的应用程序中的内存泄漏,我追逐了一个我无法理解的行为。 我分配一个大的内存块,但它不会得到垃圾收集导致一个OOM,除非我显式空onDestroy引用。

在这个例子中,我有两个几乎相同的活动,在彼此之间切换。 两者都有一个button。 按下buttonMainActivity通过调用finish()来启动OOMActivity和OOMActivity返回。 几次按下button之后,Android会抛出一个OOMException。

如果我将onDestroy添加到OOMActivity并显式地null对内存块的引用,我可以在日志中看到内存被正确释放。

为什么内存不能自动释放而没有归零?

主要活动:

package com.example.oom; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity implements OnClickListener { private int buttonId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); System.gc(); Button OOMButton = new Button(this); OOMButton.setText("OOM"); buttonId = OOMButton.getId(); setContentView(OOMButton); OOMButton.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == buttonId) { Intent leakIntent = new Intent(this, OOMActivity.class); startActivity(leakIntent); } } } 

OOMActivity:

 public class OOMActivity extends Activity implements OnClickListener { private static final int WASTE_SIZE = 20000000; private byte[] waste; private int buttonId; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Button BackButton = new Button(this); BackButton.setText("Back"); buttonId = BackButton.getId(); setContentView(BackButton); BackButton.setOnClickListener(this); waste = new byte[WASTE_SIZE]; } public void onClick(View view) { if (view.getId() == buttonId) { finish(); } } } 

Solutions Collecting From Web of "大内存块没有垃圾收集"

活动销毁并不意味着类破坏,只是因为你没有看到类并不意味着操作系统(Android在这种情况下)失去了所有的引用,并结束它。 这就是为什么即使在他们指定的文件中清除任何手柄和对象,你不再需要防止内存泄漏。 干杯。

一些东西:

1)不能仅仅通过观察GC日志来判断你的Activity是否被泄露; 每个JVM实现都可以自由select何时垃圾收集对象,即使没有引用它们。 请注意,它必须在引发OOM错误之前进行垃圾收集……但是如果它有足够的可用内存,它可以select将10个活动保留在内存中,然后一次收集它们。

2)可能有内部的Android结构,比Activity的生命周期更长地引用您的Activity,开发人员无法控制。 出于这个原因,build议Activity不要引用任何大量的数据(或者如果是这样的话,它应该在onDestroy中明确地释放这些引用(如果你想更积极的话,甚至在onPause中)。

3)一些JVM在运行时进行优化,从而永远不会写入或访问的内存块实际上不会被分配到物理内存中。 也许因为这个原因,你的testing在新版本的Android上无效。 为了解决这个问题,你可以添加一个循环,将数组中的某些值设置为随机值,然后在代码中的另一个循环中读取它们; 这样JVM就被迫分配内存。