以下示例中的内存泄漏。
1.SpeedHelper.java:
public class SpeedHelper {
interface Listener {
void OnSelected(String entry);
}
static Listener sListener;
static void setListener(Listener listener) {
sListener = listener;
}
static Listener getListener() {
return sListener;
}
static void clearListener() {
sListener = null;
}
}
2.CallSpeed.java
public class CallSpeed {
protected void speed() {
SpeedHelper.Listener litener = SpeedHelper.getListener();
if (litener != null) {
litener.OnSelected("mEntry");
}
}
}
3.MainActivity.java
public class MainActivity extends Activity {
private CallSpeed callspeed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SpeedHelper.setListener(mCallSpeedListener);
callspeed = new CallSpeed();
callspeed.speed();
}
private SpeedHelper.Listener mCallSpeedListener = new SpeedHelper.Listener() {
@Override
public void OnSelected(String entry) {
Toast.makeText(getApplicationContext(), entry, Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
SpeedHelper.clearListener();
}
}
如何避免“sListener”的内存泄漏?
答案 0 :(得分:1)
您可以尝试在static WeakReferences<Listener> sListener
类中使用SpeedHelper
进行变量定义,并将getter和setter方法更改为:
static void setListener(Listener listener) {
sListener = new WeakReference(listener);
}
static Listener getListener() {
return sListener.get();
}
答案 1 :(得分:1)
您的问题在于以下与静态字段sListener
相关联的非静态封闭匿名类:
private SpeedHelper.Listener mCallSpeedListener = new SpeedHelper.Listener() {
@Override
public void OnSelected(String entry) {
Toast.makeText(getApplicationContext(), entry, Toast.LENGTH_SHORT).show();
}
};
因为这是一个非静态的封闭类,所以它包含对其外部类MainActivity
的引用。此隐藏引用阻止GC释放MainActivity
类,因为包含隐藏引用的对象mCallSpeedListener
将使用指令{{1}存储在静态字段sListener
中}。因此,永远不会收集SpeedHelper.setListener(mCallSpeedListener);
对象,永远不会调用其MainActivity
函数,并且所有内容都保留在内存中; GC不可及。使用静态字段是对内存泄漏敞开的大门,封闭类中存在隐藏引用(匿名或非匿名)会放大此问题。
在您的情况下,您必须删除静态字段onDestroy
或将匿名类更改为普通类;一个没有对其外sListener
类的隐藏引用,或者在活动终止时在活动的另一个回调中直接调用MainActivity
。