单例引起的内存泄露
单例在使用的时候,处理不当很容易造成内存泄露,下面是一个使用中造成内存泄露的案例。
城市选择器从本地加载数据,为了不每次打开都加载一次,这边使用了单例来管理,只加载一次,
fun showCitySelector(
activity: Activity,
onCitySelectorShowListener: OnCitySelectorShowListener,
onCitySelectedListener: OnCitySelectedListener
){
this.onCitySelectorShowListener = onCitySelectorShowListener
this.onCitySelectedListener = onCitySelectedListener
//弱应用防止内存泄露
this.activity = WeakReference(activity)
if(options1Items.size <= 0)
getCityData()
else {
showCitySelectorInternal()
}
}
在fragmentA中调用:
CitySelector.instance.showCitySelector(activity,object : CitySelector.OnCitySelectorShowListener{
override fun onCitySelectorShow() {
}
}, object : CitySelector.OnCitySelectedListener{
override fun onCitySelected(
provinceId: String?,
cityId: String?,
districtId: String?,
address: String?
) {
region_selector.setValue(address)
mProvinceId = provinceId
mCityId = cityId
mDistrictId = districtId
}
})
activity使用虚引用,但是onCitySelectorShowListener 和onCitySelectedListener 使用的是强应用,onCitySelectorShowListener 和onCitySelectedListener 是在fragmentA定义的匿名内部类,持有了fragmentA的引用,这样就相当于CitySelector单例中持有了fragmenA的引用,导致fragmentA无法回收,继而activity无法回收,造成内存泄露。
使用Profiler查看到的情况,有5个内存泄露点
MyApartmentListFragment是上面的fragmentA,打开了城市选择器。
观察它的被引用情况(勾选Show nearest GC root only):
发现ApartmentInfoEditDialog中的this$0(即匿名内部类)被CitySelector中的onCitySelectedListener对象持有了,无法回收