2012-12-15 22 views
2

内存泄漏在下面的例子。内存泄漏while setListener

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” ?

回答

1

你的问题主要表现在以下非静态封闭匿名类关联于静字段sListener

private SpeedHelper.Listener mCallSpeedListener = new SpeedHelper.Listener() { 

     @Override 
     public void OnSelected(String entry) { 
      Toast.makeText(getApplicationContext(), entry, Toast.LENGTH_SHORT).show(); 
     } 
    }; 

因为这是一个非静态封闭类,它包含其外部类,MainActivity的参考。这个隐藏的参考块MainActivity类由GC释放,因为对象mCallSpeedListener - 包含隐藏的参考 - 获取存储在静态字段sListener与指令SpeedHelper.setListener(mCallSpeedListener);。因此,MainActivity对象永远不会被收集,它的onDestroy函数永远不会被调用,并且所有内容都保留在内存中; GC无法使用。使用静态字段是内存泄漏的大门,封闭类中的隐藏引用(匿名或不匿名)会放大此问题。

在你的情况,你将不得不要么删除静态字段sListener或更改匿名类普通类;一个没有对其外部MainActivity类的隐藏引用,或者在终止该活动的另一个回调时直接调用clearListener

+0

“直接调用clearListener在另一个活动回调时终止”,我没有得到这个。 – user1905715

+0

私人SpeedHelper.Listener mCallSpeedListener =新SpeedHelper.Listener(){ @Override 公共无效OnSelected(字符串条目){ Toast.makeText(getApplicationContext(),条目,Toast.LENGTH_SHORT).show(); 'SpeedHelper.clearListener(); mCallSpeedListener = NULL;' } }; 是否正确? – user1905715

+0

对于我关于使用onDestroy或onPause等onDestroy以外的其他内容的评论,它已经是深夜了,onDestroy并没有真正与GC过程绑定:即使GC不能收集活动的记忆,它也会被调用。你是如何确定sListener存在内存泄漏的? – SylvainL

1

你可以尝试在SpeedHelper类使用static WeakReferences<Listener> sListener变量定义和改变你的getter和setter方法:

static void setListener(Listener listener) { 
    sListener = new WeakReference(listener); 
} 
static Listener getListener() { 
    return sListener.get(); 
} 
+0

我不确定这是否足够:如果您还没有提供强有力的参考资料,则在您仍然需要时,可能会收集GC收集的对象sListener。但是,如果将MainActivity对象的强引用添加到sListener对象,则不再需要此静态引用。 – SylvainL