[Android] 内存泄漏示例

206 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

Android应用程序中常见的内存泄漏包括:

  1. 静态变量:如果应用程序中有静态变量,并且这些变量引用了对象,那么这些对象将不会被垃圾回收器回收,因此可能会导致内存泄漏。
  2. 循环引用:如果两个对象互相引用,并且这些对象都不会被其他对象引用,那么它们将无法被垃圾回收器回收,导致内存泄漏。
  3. 长生命周期的对象:如果应用程序中有长生命周期的对象,并且这些对象引用了其他对象,那么这些对象将不会被垃圾回收器回收,导致内存泄漏。
  4. 监听器和回调:如果应用程序中有监听器或回调,并且这些监听器或回调引用了其他对象,那么这些对象将不会被垃圾回收器回收,导致内存泄漏。

由静态变量导致的android内存泄漏

示例代码:

class MyActivity: Activity() {
    companion object {
        // 静态变量
        private static var myObject: MyObject? = null
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 分配内存
        myObject = MyObject()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 未释放内存
    }
}

在这段代码中,MyActivity类中定义了一个静态变量myObject,并在onCreate方法中分配了内存。但是,在onDestroy方法中并没有释放内存,因此会导致内存泄漏。

为了避免这种情况,应该在不再使用对象时正确地释放内存,例如:

class MyActivity: Activity() {
    companion object {
        // 静态变量
        private static var myObject: MyObject? = null
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 分配内存
        myObject = MyObject()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 释放内存
        myObject = null
    }
}

在这段代码中,我们在onDestroy方法中将myObject设置为null,从而释放了内存。这样就可以避免由于静态变量导致的内存泄漏。

由循环引用导致的android内存泄漏

示例代码:

class MyClass {
    // 循环引用
    var other: OtherClass? = null
}

class OtherClass {
    // 循环引用
    var myClass: MyClass? = null
}

fun main() {
    val myClass = MyClass()
    val otherClass = OtherClass()
    myClass.other = otherClass
    otherClass.myClass = myClass

    // 内存泄漏,因为 myClass 和 otherClass 都互相引用,垃圾回收器无法回收它们
}

在这段代码中,MyClassOtherClass之间存在循环引用。因此,在main函数中分配的内存将无法被垃圾回收器回收,导致内存泄漏。

为了避免这种情况,应该尽量避免循环引用,或者在不再使用对象时正确地释放内存。例如,可以将上述代码修改如下:

class MyClass {
    // 弱引用
    var other: OtherClass? = null
}

class OtherClass {
    // 弱引用
    var myClass: MyClass? = null
}

fun main() {
    val myClass = MyClass()
    val otherClass = OtherClass()
    myClass.other = otherClass
    otherClass.myClass = myClass

    // 使用弱引用后,myClass 和 otherClass 将被垃圾回收器回收
}

在这段代码中,我们使用了弱引用来避免循环引用。这样,当MyClassOtherClass不再被其他对象引用时,它们将被垃圾回收器回收,从而避免内存泄漏。

由长生命周期导致的android内存泄漏

示例代码:

class MyApplication: Application() {
    // 长生命周期对象
    private val myObject = MyObject()
}

class MyActivity: Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 分配内存
        val myObject = MyObject()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 释放内存
        myObject.close()
    }
}

在这段代码中,MyApplication类中的myObject对象具有长生命周期。当MyActivity对象被创建时,它也会分配内存。但是,当MyActivity对象被销毁时,它所分配的内存会被释放,而MyApplication中的myObject对象并没有被释放,导致内存泄漏。

为了避免这种情况,应该尽量避免使用长生命周期的对象,或者在不再使用对象时正确地释放内存。例如,可以将上述代码修改如下:

class MyApplication: Application() {
    // 长生命周期对象
    private val myObject = MyObject()

    override fun onTerminate() {
        super.onTerminate()
        // 释放内存
        myObject.close()
    }
}

class MyActivity: Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 分配内存
        val myObject = MyObject()
    }

    override fun onDestroy() {
        super.onDestroy()
        // 释放内存
        myObject.close()
    }
}

在这段代码中,我们在MyApplicationonTerminate方法中释放了myObject的内存,从而避免内存泄漏。

由监听器和回调导致的android内存泄漏

示例代码:

class MyClass {
    // 监听器
    var listener: MyListener? = null

    fun doSomething() {
        listener?.onSomethingDone()
    }
}

interface MyListener {
    fun onSomethingDone()
}

class MyActivity: Activity(), MyListener {
    private val myClass = MyClass()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 设置监听器
        myClass.listener = this
    }

    override fun onSomethingDone() {
        // 处理事件
    }

    override fun onDestroy() {
        super.onDestroy()
        // 未释放内存
    }
}

在这段代码中,MyActivity实现了MyListener接口,并将自身设置为MyClass的监听器。当MyClassdoSomething方法被调用时,会触发onSomethingDone方法的回调。但是,在MyActivityonDestroy方法中没有释放内存,导致内存泄漏。

为了避免这种情况,应该在不再使用监听器或回调时正确地释放内存。例如,可以将上述代码修改如下:

class MyClass {
    // 监听器
    var listener: MyListener? = null

    fun doSomething() {
        listener?.onSomethingDone()
    }
}

interface MyListener {
    fun onSomethingDone()
}

class MyActivity: Activity(), MyListener {
    private val myClass = MyClass()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // 设置监听器
        myClass.listener = this
    }

    override fun onSomethingDone() {
        // 处理事件
    }

    override fun onDestroy() {
        super.onDestroy()
        // 释放内存
        myClass.listener = null
    }
}

在这段代码中,我们在MyActivityonDestroy方法中将myClass的监听器设置为null,从而释放了内存。这样就可以避免由于监听器和回调导致的内存泄漏。