Android的内存泄漏分析

news2024/12/23 17:34:05

目录

1、内存详情

1.1、内存溢出

1.2 、内存泄漏

1.3、内存抖动

2、垃圾回收机制

2.1、垃圾回收算法(标记--清除) 

2.2、垃圾回收算法(标记--整理) 

2.3、复制算法 

2.4、分代回收算法

3.GCRoot原理

3.1、可达性分析法 

3.2、引用计数法 


1、内存详情

1.1、内存溢出

内存溢出: 指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory

Android系统为每个应用程序申请到的内存有限,一般为64M或者128M等,我们可以在清单文件中进行配置,android:largeheap = "true" 从而给APP申请更大的内存空间;给APP申请更大的内存空间。 

内存溢出又分为 : 堆内存溢出,   栈内溢出。  

虚拟机: JVM的作用是把平台无关的.class里面的字节码翻译成平台相关的机器码,来实现跨平台。Dalvik和Art就是安卓中使用的虚拟机。

项目中出现内存溢出几种情况:

  1. 1、代码中存在死循环或递归调用没有退出机制 。
  2. 2、有大循环重复产生新对象实体。
  3. 3、List、MAP等集合对象一次性加载数据过多。 
  4. 4、List、MAP等集合对象是否有使用完后,未清除的问题,使得存储的对象有引用一直无法被GC 问题。 
  • Android开发中应对内存溢出的几种方法:  
  • 1.、大量位图加载。 
  • 2、位图对象没有及时释放。 
  • 3、查询数据库没有及时关闭游标。 
  • 4、使用Adapter时候没有缓存convertView。 
  • 5、采用二级缓存机制 
  • 6、 等比例缩小位图文件 
  • 7、优化虚拟机堆内存 
  • 8、强制回收内存信息。System.gc() 

1.2 、内存泄漏

内存泄漏:指程序在申请内存后,被某个对象一直持有,无法释放已申请的内存空间。

       一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。单例模式在Android开发中会经常用到,但是如果使用不当就会导致内存泄露。因为单例的静态特性使得它的生命周期同应用的生命周期一样长,如果一个对象已经没有用处了,但是单例还持有它的引用,那么在整个应用程序的生命周期它都不能正常被回收,从而导致内存泄漏。

简单的内存泄漏检测方法:  在重复打开关闭某一个Activity时候,发现内存占比一直在攀升,说明有些应该释放的内存没有及时释放。 

Android常见的几种内存泄漏:  

1、 静态变量导致内存泄漏。静态变量存储在方法区,生命周期从类加载开始到整个进程结束。 一但静态变量初始化后,它所持有的引用只有等待进程结束才会释放。 

2、非静态内部类导致内存泄漏 。 非静态内部类包括匿名内部类默认持有外部类引用,当非静态内部类对象生命周期比外部对象的生命周期长时,就会导致内存泄漏。 Android在Handler,Thread 使用上最容易导致内存泄漏。 

3、未取消注册或回调导致内存泄漏。  比如在Activity中注册广播,但是在Activity销毁后不取消注册,那么广播系统会一直存在系统中,且引用着Activity,从而导致内存泄漏。

4、集合中对象未清理导致内存泄漏。 假设某个对象被添加到了集合中,也就是集合引用了这个对象,此时这个对象是无法被GC的。

5、资源未关闭或者释放导致内存泄漏。 在使用流或者资源时要及时关闭,资源读写操作通常都是使用了缓冲,这些缓冲对象就会一直被占用得不到释放,以致于内存泄漏。

1.3、内存抖动

内存抖动:  是指在短时间内有大量的对象被创建或者被回收的现象,内存抖动出现原因主要是频繁(很重要)在循环里创建对象(导致大量对象在短时间内被创建,由于新对象是要占用内存空间的而且是很频繁。 

Android内存抖动解决方法 

 1、尽量避免在循环体内创建对象,应该把对象创建移到循环体外。

 2、自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象

 3、当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用 

 4、对于能够复用的对象,同理可以使用对象池将它们缓存起来

2、垃圾回收机制

 jvm与Android关系 

    JVM以Class为执行单元,Android虚拟机以Dex执行单元,编译流程JVM直接通过Javac即可加载。Android虚拟机需要先编译成dex,然后编译成apk。最后执行Android  Art虚拟机在安装的时候讲dex缓存本地机器码,安装比较慢,耗存储空间。  Android  Dalvik虚拟机在程序运行过程中进行翻译。节省空间,耗cpu时间。以空间换时间的典型

2.1、垃圾回收算法(标记--清除) 

GC分为2个阶段

标记和清除,首先标记所有可回收的对象,在标记完成后统一回收所有被标记的对象,会产生不连续的内存碎片。 碎片过多会导致以后程序运行时需要分配较大对象是,无法找到足够的连续内存,而不得已再次触发GC,或者直接在开辟新的连续内存,导致内存浪费。  

标记阶段:  垃圾回收器会从mutator(应用程序)根对象开始遍历。每一个可以从根对象访问到的对象都会被添加一个标识,于是这个对象就被标识为可到达对象  。

清除阶段:垃圾回收器,会对堆内存从头到尾进行线性遍历,如果发现有对象没有被标识为可到达对象,那么就将此对象占用的内存回收,并且将原来标记为可到达对象的标识清除,以便进行下一次垃圾回收操作 。

特别说明:在垃圾回收阶段,应用程序的执行会暂停,等待回收执行完毕后,再恢复程序的执行。

缺点:  执行不稳定,内存空间碎片化问题。  

2.2、垃圾回收算法(标记--整理) 

标记—整理算法(回收老年代使用此方法)定义: 

      ​ 标记:标记出所有需要回收的对象/或标记存活的对象。

      ​ 整理:让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存。

区别:

​     标记-清除算法是一种非移动式的回收算法。 

     标记—整理算法是移动式的。

​ 缺点:如果移动存活对象,尤其是在老年代这种每次回收都有大量对象存活区域,移动存活对象并更新。所有引用这些对象的地方将会是一种极为负重的操作;而且这种对象移动操作必须全程暂停用户应用程序才能进行。像这样的停顿被最初的虚拟机 设计者形象地描述为“Stop The World”(Stop The World非常影响系统的响应时间)。

2.3、复制算法 

原理:将内存空间分为两块,每次只使用其中一块,在垃圾回收的时候,将正在使用的内存中的存活对象复制到未被使用的内存块中,之后清除正在使用的内存块,交换两个内存角色。

缺点:
1、需要两倍空间。
2、GC需要维护对象的引用关系,时间开销加大此种方案使用与垃圾对象较少,量级不大的情况

 

2.4、分代回收算法

   为了满足垃圾回收的效率最优性,分代手机算法基于一个事实:不同的对象生命周期是不一样的,因此,不同生命周期的对象可以采取不同的手机方式,以便于提高回收效率。

     一般是把JAVA堆分为新生代和老年代,这样就可以根据各个年代的特点使用不同回收算法,相对提高效率在系统运行过程汇总,会产生大量对象,其中有些对象是业务信息相关,如HTTP请求的Session、线程、Socket连接等对象,这类对象跟业务挂钩,因此生命周期长,还有一部分是运行过程汇总生成的临时变量,这些对象生命周期短,比如:String,这些对象甚至只使用一次即可回收 。 

目前所有GC都采用分代收集算法进行执行
对象的状态经过大量的调研研究划分为年青代与老年代两个类别
(1)、年轻代:区域相对小,对象生命周期短、存活率低,且产生应用频繁
复制算法回收整理速度是最快的。复制算法效率只与当前存活对象大小有关,因此很实用与年青代的回收,而空间问题,因为存活率问题,所以单独开辟S0,S1两块空间处理清除后结果
(2)、老年代:区域较大,生命周期长、存活率高,回收不及年青代频繁 。

 

3.GCRoot原理

1.JVM内存划分为堆内存和非堆内存,堆内存分为年轻代、老年代,非堆内存就一个永久代(方法区)。
2.年轻代又分为Eden和Survivor区。Survivor区由FromSpace和ToSpace组成。Eden区占大容量,Survivor两个区占小容量,默认比例是8:1:1。
3.堆内存用途:存放的是对象,垃圾收集器就是收集这些对象,然后根据GC算法回收。
4.非堆内存用途:永久代,也称为方法区,存储程序运行时长期存活的对象,比如类的元数据、方法、常量、属性等。
GC Root原理:通过对枚举GCroot对象做引用可达性分析,即从GC root对象开始,向下搜索,形成的路径称之为 引用链。如果一个对象到GC roots对象没有任何引用,没有形成引用链,那么该对象等待GC回收。
GC Root对象 : 

1、虚拟机栈(javaStack)(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。

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

3、方法区中常量引用的对象。

4、本地方法栈中JNI(Native方法)引用的对象。

3.1、可达性分析法 

相对于引用计数算法,他有效的解决了在引用计数算法中的循环引用问题,防止内存泄漏发生

这种类型的垃圾收集也叫作追踪性垃圾收集

概念:
(1)可达性分析算法以跟对象集合为起点,按照从上至下的方式搜索被跟对象集合所链接的对象目标是否可达
(2)使用可达性分析算法后,内存中的存货对象会被跟对象集合直接或者间接连接着,搜索所走过的路径称之为引用链
(3)如果目标对象没有任何阴影链项链,则是不可达的,意味着该对象已经死亡,可以标记为垃圾对象。
在可达性分析算法中只有能够被根对象集合直接或间接连接的对象才是存活对象

3.2、引用计数法 

原理:对每一个对象保存一个整形的引用计数器属性,用于记录对象被引用的情况。

优点:实现简单,垃圾对象便于识别,判断效率高

缺点:他需要单独的字段存储计数器,这样的做法增加的存储空间的开销
每次赋值需要额外的加减法计算,增加了时间开销
引用计数算法最大的问题是无法处理循环引用的情况,这是一个比较致命的缺陷

参考文章:

JVM10_引用计数法、GCROOT、Finalization机制、复制、标记清除、标记压缩算法、分代收集、增量收集、分区算法(一)-阿里云开发者社区

 内存泄漏_百度百科

Java垃圾回收机制(GC原理)解析_分代手机算法_浮空over的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/744533.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VSCODE 设置同步network Error 问题

前言 这个问题等解决方法如下: 获取到github以及vscode-auth.github.com的ip,添加到host,随后使用命令行刷新host,重新认证即可 第一步,查看log文件, 打开 vscode,使用快捷指令ctrl(command)…

对象池介绍

对象池介绍 对象池是一种常见的优化技术,用于减少游戏运行时的内存分配和垃圾回收。对象池维护了一组已经创建的对象实例,这些对象可以被多次重复使用,而不需要每次都重新创建和销毁。对象池的主要优点是可以减少内存分配和垃圾回收的次数&a…

第一百零四天学习记录:C++核心:类和对象Ⅶ(五星重要)继承下

继承同名成员处理方式 1、访问子类同名成员&#xff0c;直接访问即可 2、访问父类同名成员&#xff0c;需要加作用域 #include<iostream> using namespace std; class Base { public:Base(){m_A 100;}int m_A;void func(){cout << "Base - func()调用"…

途乐证券-逆市拉升!这一板块超10股涨停

7月12日&#xff0c;A股商场全体走低&#xff0c;个股跌多涨少&#xff0c;厄尔尼诺的冲击波也“搅动”了A股商场&#xff0c;种业、虚拟电厂等概念股纷繁走强。轿车产业链个股继续活泼&#xff0c;超10股涨停。 2023年中期成绩预告仍如火如荼发表中&#xff0c;成绩“预喜”股…

SpringCloud入门实战(十三)Nacos服务注册与发现+配置管理详解

&#x1f4dd; 学技术、更要掌握学习的方法&#xff0c;一起学习&#xff0c;让进步发生 &#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我&#xff0c;不迷路 。 &#x1f490;学习建议&#xff1a;1、养成习惯&#xff0c;学习java的任何一个技术…

电脑网络最基本的常识简介(合集)

电脑网络最基本的常识简介 什么是HTML? HTML(Hyper Text Mark-up Language )即超文本标记语言&#xff0c;是 WWW 的描述语言&#xff0c;由 Tim Berners-lee提出。设计 HTML 语言的目的是为了能把存放在一台电脑中的文本或图形与另一台电脑中的文本或图形方便地联系在一起&a…

蚁群算法—ACA

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; 目录 一、蚁群算法简介&#x1f353;1.ACA基本思想2.ACA基本原理3.ACA基本步骤 二、算法求解TSP问题&#x1f34e;1.导入数据2.计算城市间相互距离3.初始化参数4.迭代寻找最佳路径5.结果显示End 一、蚁群算法简介&a…

软件 - 配置安装 Photoshop 的 RID 独立运行版本

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/131673004 Adobe Photoshop 是一款专业的图像处理软件,广泛应用于平面设计、摄影、插画、视频制作等领域,可以对各种格式的图片进行编辑、修饰、合成、优化等操作,创…

SpringBoot + Vue 实现酒店客房管理系统

目录 1 问题的提出 5 2系统开发的可行性研究 6 2.1 技术上可行性分析 6 系统现阶段的发展过程中&#xff0c;利用现有人力和物力是完全具备的能力开发出来 6 2.2 经济的可行性分析 6 2.3 操作可行性分析 6 3 需求分析 7 3.1 需求描述 7 3.2 功能需求分析 7 3.3 非功能需求分析…

JDBC学习笔记

目录 一、JDBC 1&#xff1a;为什么要学习JDBC技术 2、JDBC技术概述与理解 3、JDBC使用步骤分析 3.1、注册驱动 3.2 、获取连接 3.3、创建发送sql语句对象 3.4、发送sql语句 3.5、结果集解析 3.6、资源关闭 一、JDBC 1&#xff1a;为什么要学习JDBC技术 1、Java和数…

【雕爷学编程】Arduino动手做(117)---P10V706LED屏模组3

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

亚马逊买家号如何绑定信用卡

要在亚马逊上绑定信用卡作为买家号的支付方式&#xff0c;请按照以下步骤进行操作&#xff1a; 1、登录亚马逊账户&#xff1a;使用您的亚马逊账户用户名和密码登录到亚马逊网站。 2、导航至"我的账户"&#xff1a;在页面右上角&#xff0c;将鼠标悬停在"你好…

安装使用docker-compose

Docker-Compose项目是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排 Docker-Compose将所管理的容器分为三层&#xff0c;分别是工程&#xff08;project&#xff09;&#xff0c;服务&#xff08;service&#xff09;以及容器&#xff08;container&…

【单周期CPU】LoongArch | LA32R | 二选一控制器MUX | 数据通路

前言&#xff1a;本章内容主要是演示在vivado下利用Verilog语言进行单周期简易CPU的设计。一步一步自己实现模型机的设计。本章先介绍单周期简易CPU中数据通路的设计。 &#x1f4bb;环境&#xff1a;一台内存4GB以上&#xff0c;装有64位Windows操作系统和Vivado 2017.4以上版…

华为OD机试真题 Java 实现【矩阵中非1的元素个数】【2023 B卷 200分】,附详细解题思路

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明先将[0,0]位置的值变为1。第一次同化&#xff1a;第二次同化&#xff1a; 大家好&#xff0c;我是哪吒。 一、题目描述 存在一个m*n的二维数组&#xff0c;其成员取…

小程序项目时间选择器用法

项目需求是要实现这种形式, 但是相信大家都试了各种插件,都不太合适,uView框架也不能满足自己的需要; 推荐使用:uview-ui-plus 基本上小程序遇到的单选多选 日期 省市区 都可以完美的实现,可以通过插件市场安装使用 但是要实现ui给的原型图 还需要做一下调整 弹性布局给两个选…

Linux查找关键字出现的位置

在Linux中&#xff0c;您可以使用以下命令来查找文件中关键字出现的位置&#xff1a; grep -rnw /path/to/search -e keyword其中&#xff1a; - -r 递归地搜索指定路径下的所有子目录。 - -n 显示匹配行的行号。 - -w 完整匹配单词&#xff0c;而不是部分匹配。 - /path/to/s…

pandas 重复数据处理详解

概要 重复值处理主要涉及两个部分&#xff0c;一个是找出重复值&#xff0c;第二个是删除重复值&#xff0c;也就是根据自己设定的条件进行删除操作。本次来介绍关于重复数据处理的几个常用方法。 定位重复值 对于重复值&#xff0c;我们首先需要查看这些重复值是什么样的形式…

LFU算法的详细介绍与实现

LRU 算法的淘汰策略是 Least Recently Used&#xff0c;也就是每次淘汰那些最久没被使用的数据&#xff1b;而 LFU 算法的淘汰策略是 Least Frequently Used&#xff0c;也就是每次淘汰那些使用次数最少的数据。 LRU 算法的核心数据结构是使用哈希链表 LinkedHashMap&#xff…