override fun onDestroy() {
super.onDestroy()
// clear context reference to avoid memory leaks
Utils.context = null
}
}object Utils {
// memory leaks can happen here
var context: Context? = nullfun doSomethingWithContext(){
context?.apply {
// doing wonderful things with the context
}
}
}### 长期运行任务
Android中的活动和碎片具有相当复杂的生命周期。在错误的时间做这项工作可能会导致内存泄漏。如果活动启动后台任务,并且该任务在活动被销毁时继续运行,则垃圾回收器可能不会收集该活动。如果在异步回调中引用了某些视图,则在任务完成之前无法释放这些视图。这意味着包含视图的活动以及活动中的所有对象都会泄漏。因此,当不再需要长时间运行的任务时,应该取消它。class MainActivity : AppCompatActivity() {
private lateinit var textView: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)TaskExecutors.doTask(10, object: (Int) -> Unit {
override fun invoke(result: Int) {
// this may cause memory leaks or even crashes if the task is still running after the activity has been killed
runOnUiThread {
textView.text = result.toString()
}
}
})}
override fun onDestroy() {
super.onDestroy()
// should cancel running tasks if it is not needed anymore
TaskExecutors.cancelTask()
}
}object TaskExecutors {
private var job: Job? = null
fun doTask(input: Int, callback: (Int) -> Unit) {
job = GlobalScope.launch {
val result = doHeavyCalculation(input)
callback.invoke(result)
}
}private suspend fun doHeavyCalculation(input: Int): Int {
delay(10000L)
return input * 10
}fun cancelTask(){
// find a way to cancel long-running task
}
}### 未关闭资源
无论何时创建或打开资源,系统都会为这些资源分配内存。不关闭这些资源会阻塞内存,使它们无法被收集。这些类型的一些示例包括数据库连接、输入流或忘记注销广播接收器。
### 非静态内部类
内部类的任何实例都包含对其外部类的隐式引用。如果内部类的实例比外部类的生存时间长,则会发生内存泄漏。更具体地说,存在这样一种情况:内部对象是活动的(通过引用),但对包含对象的引用已经从所有其他对象中移除。内部对象仍然保持包含对象的活动状态,因为它始终具有对它的引用。fun main(args: Array) {
val productContainer = mutableListOf<Factory.Product>()// need a factory to make product
val factory = Factory()for (i in 0…10000) {
val newProduct = factory.createProduct()
productContainer.add(newProduct)
}// create product complete, now we don’t need the factory anymore. But…
// … the factory is still here, because the product has the reference to it.
}class Factory {
// data to leak
var data = 0fun createProduct(): Product = Product()
inner class Product { var pId: Int = 0 }
}