android自定义监听导致内存泄漏问题,Android—常见的内存泄漏场景及解决方案

本文探讨了Android中常见的内存泄漏场景,包括非静态内部类、匿名内部类、多线程、视图、广播和监听器等导致的问题,并提供了相应的解决方案。通过理解Java的内存管理和垃圾回收机制,开发者能更好地诊断和修复内存泄漏问题,提高应用性能。
摘要由CSDN通过智能技术生成

我的CSDN: ListerCi

我的简书: 东方未曦

一、引言

一般情况下Android的内存泄漏是因为,存在引用指向一个本该被回收的对象,例如已经执行onDestroy()的Activity。在这种情况下,由于Activity内某些对象的生命周期比Activity要长,在Activity理论上被销毁时,该对象依旧存在并持有Activity的引用,因此内存回收机制(GC)无法释放Activity,最终导致内存泄漏。

为了发现和修复APP中存在的内存泄漏,开发人员会在APP上安装内存检测工具(如leakcanary),当出现内存泄漏时,该工具会提供一个报告,里面包含了一条引用链,指明可能造成内存泄漏的引用。开发人员需要在合适的地方切断引用链,以便GC释放掉没有被引用的对象。

有些内存泄漏的修复很简单,将非静态内部类内部类改为静态内部类或者将Context改为ApplicationContext后检测工具就检测不出内存泄漏了,但是这到底是为什么呢?而且就算检测工具检测不出内存泄漏,就真的万无一失了吗?

带着这些问题,我们来分析一下Android常见的内存泄漏场景以及解决方案。

二、Java内存管理及垃圾回收机制

在了解Android的内存泄漏之前,我们需要先了解Java的内存管理以及垃圾回收机制。

2.1 内存管理

Java的内存分配区域主要分为以下几个部分。

1. 静态变量区

用于存储被static修饰的静态变量,这块区域在程序开始运行时就已经分配完毕,并且存在于程序的整个运行过程。

2. 栈

主要用于分配局部变量,包括基本类型的变量和对象的引用变量,当局部变量的作用域结束之后,Java会自动释放掉该变量占用的内存空间。

3. 堆

堆是动态内存区域,程序运行期间新建的对象实例和数组都存储在堆中,垃圾回收机制(GC)管理的就是这块内存。为了及时地将不被使用的对象释放掉,GC需要监控每一个对象的状态,当一个对象不再被引用时,GC就会释放该对象。

4. 常量池

常量池中的内容在编译时就已经确定,主要包含代码中的基本类型和对象类型的常量值。

例如,String就是对象类型,如果在编译时确定了String的值(String s = "test"),那么它的值就存储在常量池中,而它的引用存储在栈中。如果String的值是在程序运行时确定的(String s = new String("...")),那么它的值就存储在堆中。

假设当前有一个实例A存储在堆中,我们定义了一个引用a指向实例A。此时引用a其实是保存在栈中的,它的值为实例A在堆内存中的首地址,此时程序就可以通过a读写A的值。

2.2 垃圾回收机制

上面提到,当一个对象不再被引用时,GC就应该将其回收。确实有一种引用计数法来判断一个对象是否需要被释放,当该对象的引用计数为0时代表它需要被回收。但是如果存在两个对象,没有别的引用指向它们,但是它们互相引用,此时它们的引用计数都不为0,导致无法释放,容易造成内存泄漏。

目前主流的的方法是通过可达性分析来判断一个对象是否需要被释放。该算法的基本思路就是通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。

在Java中,可作为GC Root的对象包括以下几种:

虚拟机栈(栈帧中的本地变量表)中引用的对象

方法区中类静态属性引用的对象

方法区中常量引用的对象

本地方法栈中JNI(即一般说的Native方法)引用的对象

三、Android常见内存泄漏场

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值