Android常见内存泄漏以及优化方案

Android 内存优化——常见内存泄露及优化方案 熟悉Handler消息机制的都知道,mHandler会作为成员变量保存在发送的消息msg中,即msg持有mHandler的引用,而mHandler是Activity的非静态内部类实例,即mHandler持有Activity的引用,那么我们就可以理解为msg间接持有Activity的引用。在Android开发中,静态持有很多时候都有可能因为其使用的生命周期不一致而导致内存泄漏,所以我们再新建静态持有的变量的时候需要多考虑一下各个成员之间的引用关系,并且尽量少地使用静态持有的变量,以避免发生内存泄漏。 阅读详情

单例导致内存泄漏
首先来看一下一种单例的写法:多种单例写法参考

	public class Utils{
		private static Utils mInstance;
		private Context mContext;
		private Utils(Context context){
			this.mContext = context;
		}
		public static Utils getInstance(Context context){
			if(mInstance == null){
				Util = new Utils(context);
			}
			return mInstance;
		}
	}

以Activity为例,当我们启动一个Activity,并调用Utils.getInstance(Context context),传入Activity.this作为context,这样Utils类的单例mInstance就持有了Activity的引用,当我们退出Activity时,该Activity就没有用了,但是因为mIntance作为静态单例(在应用程序的整个生命周期中存在)会继续持有这个Activity的引用,导致这个Activity对象无法被回收释放,这就造成了内存泄露。
为了避免这样单例导致内存泄露,我们可以将context参数改为全局的上下文:

	private Utils(Context context){
				this.mContext = context.getApplicationContext();
	}

全局的上下文Application Context就是应用程序的上下文,和单例的生命周期一样长,这样就避免了内存泄漏。单例模式对应应用程序的生命周期,所以我们在构造单例的时候尽量避免使用Activity的上下文,而是使用Application的上下文。

非静态内部类导致内存泄漏
我们都知道内部类会持有外部类引用。 原因通过编译查看.class文件可知,编译器会为内部类构造传入外部类实例.所以非静态内部类会持有外部类引用。
这样在特定情况下就会产生一个问题。就是如果内部类的生命周期比外部类的生命周期长,那么在外部类无用时,内部类依然持有外部类引用,导致外部类无法释放,从而导致内存泄漏。
Android 中典型的使用场景就是Handler.通常我们的写法是这样:

	public class MainActivity extends AppCompatActivity{
		@Override
		protected void onCreate(Bundle savedInstanceState){
			super.onCreate(savedInstanceState);
			setContentView(R.layout.activity_main);
			start();
		}
		private void start(){
			Messagemsg=Message.obtain();
			msg.what=1;
			mHandler.sendMessage(msg);
		}
		private Handler mHandler=new Handler(){
			@Override
			public void handleMessage(Message msg){
				if(msg.what==1){
				//做相应逻辑
			}
			}
		};
	}

熟悉Handler消息机制的都知道,mHandler会作为成员变量保存在发送的消息msg中,即msg持有mHandler的引用,而mHandler是Activity的非静态内部类实例,即mHandler持有Activity的引用,那么我们就可以理解为msg间接持有Activity的引用。msg被发送后先放到消息队列MessageQueue中,然后等待Looper的轮询处理: MessageQueue和Looper都是与线程相关联的,MessageQueue是Looper引用的成员变量,而Looper是保存在ThreadLocal中的。那么当Activity退出后,msg可能仍然存在于消息对列MessageQueue中未处理或者正在处理,那么这样就会导致Activity无法被回收,以致发生Activity的内存泄露。

通常在Android开发中如果要使用内部类,但又要规避内存泄露,一般都会采用静态内部类+弱引用的方式。

在Activity中创建静态内部类:

	public class MainActivity extends AppcompatActivity{
		private static class MyHandler extends Handler{
        	private WeakReference<MainActivity> activityWeakReference;
	        public MyHandler(MainActivity activity){
	            activityWeakReference = new WeakReference<>(activity);
	        }
        	@Override
	        public void handleMessage(@NonNull Message msg) {
	            if(activityWeakReference.get() != null){
	                if(msg.what == 1 ){
	                    //do something
	                }
	            }
	        }
    }

上面的做法确实避免了Activity导致的内存泄露,发送的msg不再已经没有持有Activity的引用了,但是msg还是有可能存在消息队列MessageQueue中,所以更好的是在Activity销毁时就将mHandler的回调和发送的消息给移除掉。

	@Override
	protected void onDestroy(){
		super.onDestroy();
		mHandler.removeCallbacksAndMessages(null);
	}

非静态内部类造成内存泄露还有一种情况就是使用Thread或者AsyncTask。 同样类似于handler,生命周期的不一致导致内存泄漏。
总之,在使用内部类时,要时刻注意生命周期是否一致,如果不一致就要考虑是否会发生内存泄漏的问题。

未取消注册或回调导致内存泄露
在注册观察则模式的时候,如果不及时取消也会造成内存泄露。比如使用Retrofit+RxJava注册网络请求的观察者回调,同样作为匿名内部类持有外部引用,所以需要记得在不用或者销毁的时候取消注册

静态变量导致内存泄露
静态变量存储在方法区,它的生命周期从类加载开始,到整个进程结束。一旦静态变量初始化后,它所持有的引用只有等到进程结束才会释放。
尽量少地使用静态持有的变量,以避免发生内存泄露。当然,我们也可以在适当的时候讲静态量重置为null,使其不再持有引用,这样也可以避免内存泄露。
不要在类初始时初始化静态成员。可以考虑lazy初始化。
架构设计上要思考是否真的有必要这样做,尽量避免。如果架构需要这么设计,那么此对象的生命周期你有责任管理起来。

集合中的对象未清理造成内存泄露
这个比较好理解,如果一个对象放入到ArrayList、HashMap等集合中,这个集合就会持有该对象的引用。当我们不再需要这个对象时,也并没有将它从集合中移除,这样只要集合还在使用(而此对象已经无用了),这个对象就造成了内存泄露。并且如果集合被静态引用的话,集合里面那些没有用的对象更会造成内存泄露了。所以在使用集合时要及时将不用的对象从集合remove,或者clear集合,以避免内存泄漏

属性动画造成内存泄露
动画同样是一个耗时任务,比如在Activity中启动了属性动画(ObjectAnimator),但是在销毁的时候,没有调用cancle方法,虽然我们看不到动画了,但是这个动画依然会不断地播放下去,动画引用所在的控件,所在的控件引用Activity,这就造成Activity无法正常释放。因此同样要在Activity销毁的时候cancel掉属性动画,避免发生内存泄漏。

资源未关闭或释放导致内存泄露
在使用IO、File流或者Sqlite、Cursor等资源时要及时关闭。这些资源在进行读写操作时通常都使用了缓冲,如果及时不关闭,这些缓冲对象就会一直被占用而得不到释放,以致发生内存泄露。因此我们在不需要使用它们的时候就及时关闭,以便缓冲能及时得到释放,从而避免内存泄露
Bitmap 没调用 recycle()方法,对于 Bitmap 对象在不使用时,我们应该先调用 recycle() 释放内存,然后才它设置为 null. 因为加载 Bitmap 对象的内存空间,一部分是 java 的,一部分 C的(因为 Bitmap 分配的底层是通过 JNI 调用的 )。 而这个 recyle() 就是针对 C 部分的内存释放。

总结
内存泄露在Android内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄露我们不一定就能注意到,所有在编码的过程要养成良好的习惯。
总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:

  • 构造单例的时候尽量别用Activity的引用;
  • 静态引用时注意应用对象的置空或者少用静态引用;
  • 使用静态内部类+软引用代替非静态内部类;
  • 及时取消广播或者观察者注册;
  • 耗时任务、属性动画在Activity销毁时记得cancel;
  • 文件流、Cursor等资源及时关闭;
  • Activity销毁时WebView的移除和销毁(android5.1上的bug,当Activity销毁时,webView并没有被真正移除掉,还持有Activity的引用)。
Obsidian+llama3:终于搭建了自己的知识库 Obsidian 的 Smart Connections,超出了我原本的预期,于是结合新模型非常方便地搭建了我的个人知识库。 阅读详情

相关推荐

EPLAN中3D宏文件的创建与优化技巧(以开关电源为例)

本文以开关电源为例,详细讲解了在EPLAN中创建和优化3D宏文件(.ema)的全流程。从搭建宏项目、导入模型,到精确定义安装面、调整视野方向,再到定义3D连接点并关联部件库,旨在帮助电气工程师在设计阶段实现精准布局、避免安装冲突,从而提升设计效率与质量。

weixin_29219539的博客 548

Android 内存泄漏

内存泄漏:即memory leak。是指内存空间使用完毕后无法被释放的现象,虽然Java有垃圾回收机制(GC),但是对于还保持着引用, 该内存不能再被分配使用,逻辑上却已经不会再用到的对象,垃圾回收器不会回收它们。内存溢出:即out of memory, 当你要求分配的内存超过了系统给你的内存时, 系统就会抛出out of memory的异常(每个Android能用的内存是有限的)。比如: 当前应用只剩下4M的空间可用, 但你却加载得到一个需要占用5M空间的图片Bitmap对象, 就会抛出溢出的异常。

追梦的鱼儿 2981

MeshLab新手必看:5分钟搞定泊松表面重建(附完整点云处理流程)

本文详细介绍了如何使用MeshLab进行泊松表面重建,从点云数据导入、预处理到核心参数设置,再到后处理与模型优化,提供了完整的3D重建流程指南。特别适合计算机视觉和3D重建领域的新手快速掌握泊松重建技术,提升工作效率。

kafka6courier的博客 230

对内存溢出和内存泄露的简单总结理解

一、什么是内存溢出和内存泄露 内存泄漏(memory leak):是指程序在申请内存后,无法释放已申请的内存空间,导致系统无法及时回收内存并且分配给其他进程使用。通常少次数的内存无法及时回收并不会到程序造成什么影响,但是如果在内存本身就比较少获取多次导致内存无法正常回收时,就会导致内存不够用,最终导致内存溢出。2、内存溢出 (out of memory)::指程序申请内存时,没有足够的内存供申请...

qq_33556350的博客 1万+

VMware ESXi 7.0下Intel网卡SR-IOV配置实战:解决虚拟化网络延迟问题

本文详细介绍了在VMware ESXi 7.0环境下为Intel网卡配置SR-IOV(单根I/O虚拟化)的完整实战流程。通过硬件辅助直通技术,虚拟机可直接访问物理网卡资源,有效绕过虚拟化层瓶颈,从而显著降低网络延迟和CPU开销,适用于金融交易、实时计算等对性能敏感的场景。

embedding5hiker的博客 554

蓝牙抓包实战:用nrf52840和Wireshark解析广播包与SCAN_RSP的完整流程

本文提供了一份完整的蓝牙抓包实战指南,详细介绍了如何使用nRF52840 Dongle和Wireshark捕获并解析蓝牙广播包与SCAN_RSP。内容涵盖环境搭建、广播事件分析、数据包结构拆解以及常见连接问题的调试技巧,旨在帮助开发者和物联网工程师深入理解BLE底层通信,提升硬件调试能力。

weixin_29279153的博客 495

最常见的8个Android内存泄漏问题及解决方法

内存泄漏指的是应用程序中存在一些对象或者资源无法被垃圾回收器回收,导致内存占用不断增加,最终导致设备性能下降。

maniuT的博客 3241

实战演练,如何用Easyexcel合并单元格,设置字体、边框样式,并在尾行加入备注

,实现效果如下:1、多级表头合并2、表头底纹+表格边框3、合并相同数据单元格4、尾行加入备注。

Su7148的博客 1万+

Android内存泄漏

1 什么是内存泄漏(Memory Leak) leak [liːk] 渗入,漏出;漏,渗漏;泄露,透露 Java是垃圾回收语言的一种,其优点是开发者无需特意管理内存分配,降低了应用由于局部故障(segmentation fault)导致崩溃,同时防止未释放的内存把堆栈(Heap)挤爆的可能,所以写出来的代码更为安全。 segmentation [ˌseɡmenˈteɪʃn] 分割;割断;细胞分裂 但是,在Java中仍存在很多容易导致内存泄漏的逻辑可能(logical leak)。如果不小心,Android应

xingyu19911016的博客 4526

Xilinx Vivado vitis IDE launch Failed \ Web installer client Obsolete 怎么办

Xilinx vitis_IDE failed Web installer client Obsolete

weixin_44820962的博客 8644

OpenGL 进阶系列10 - 光线跟踪实现简介(Ray Tracing)

OpenGL 实现光线跟踪(Ray Tracing)是一个相对复杂但有趣的挑战,通常用于生成高度逼真的图像效果,如反射、折射、阴影等。OpenGL 本身并不是为光线跟踪设计的,但可以通过结合计算着色器和现代 OpenGL 功能实现光线跟踪。光线跟踪的基本思路是从相机(或视点)出发,发射光线并计算这些光线与场景中物体的交点。光线与场景中物体相交的计算。计算交点的光照(基于表面法线、光源位置、材质等)。反射和折射的处理(如果物体是透明或反射的)。

GPU全栈博主 1534

Android 内存泄漏的常见原因及其对应的解决方案

LeakCanary由Square开发,是一个强大的开源库,用于检测Android应用程序中的内存泄漏。内存泄漏是指在应用程序中不再需要的对象仍然保持对内存的引用,导致内存无法回收,从而造成内存溢出和性能问题。LeakCanary可以自动检测和报告应用程序中的内存泄漏,并提供详细的信息,帮助开发人员快速定位和修复问题。

特立独行的博客 5869

基于Python的FAO农业数据高效爬取与分析实战:从Scrapy到异步爬虫的进阶之路

本文将详细介绍如何使用Python最新技术爬取联合国粮农组织(FAO)的农业数据,涵盖从基础爬虫到高级异步爬虫的完整实现过程。文章包含5000余字的技术解析,提供完整的代码示例,并探讨数据处理与存储的最佳实践。

2201_76125261的博客 241

Android常见内存泄漏优化及解决方案

一.什么是内存泄漏? 如果一个无用对象(不需要再使用的对象)仍然被其他对象持有引用,造成该对象无法被系统回 收,以致该对象在堆中所占用的内存单元无法被释放而造成内存空间浪费,这种情况就是内存泄漏。 在 Android 开发中,一些不好的编程习惯会导致我们的开发的 app 存在内存泄露的情况。下面介 绍一些在 Android 开发中常见的内存泄露场景及优化方案。 1. 单例导致内存泄漏 单例模式在 ...

qq_20489601的博客 368

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Android内存优化,常见内存泄漏及优化方案

前言 在安卓开发中,一些不好的编程习惯会导致应用出现内存泄漏的情况。 1. 单例导致的内存泄漏 单例模式在开发中是非常常见的,但因为单例模式的静态特性使得其生命周期同应用生命周期一样长,如果一个对象没有用处了,但单例还持有它的引用,那么在整个生命周期中都不会被回收,就可能导致内存泄漏。如下代码: public class Singleton { private static Singleton singleton = null; private Context mContext; public

qq_41915623的博客 437

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

android sdk内存泄漏,Android常见内存泄漏以及优化方案

单例导致内存泄漏首先来看一下一种单例的写法:多种单例写法参考public class Utils{private static Utils mInstance;private Context mContext;private Utils(Context context){this.mContext = context;}public static Utils getInstance(Context...

weixin_42129005的博客 512

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

android内存优化方案,Android内存优化--常见的内存泄漏以及优化方案

无用的内存(没有使用的对象)仍然被其他对象持有引用,造成该对象无法被系统回收,以致该对象在堆中所占用的内存单元无法被释放而造成内存空间浪费,这中情况就是内存泄露。在开发的过程中,我们的一些编程习惯有可能会导致app内存溢出情况,下面举简单的几个例子说明:1、单利模式:单利模式在开发中我们经常使用,如果使用不当就会造成内存泄漏,单利模式都是静态的,它的生命周期一般都会很长,如果一个对象已经没有用处了...

weixin_29794879的博客 289

Android性能优化之常见内存泄漏和优化方案

本文转载自http://www.jianshu.com/p/ab4a7e353076 感谢原作者xiaoyanger 如果一个无用对象(不需要再使用的对象)仍然被其他对象持有引用,造成该对象无法被系统回收,以致该对象在堆中所占用的内存单元无法被释放而造成内存空间浪费,这中情况就是内存泄露。 在Android开发中,一些不好的编程习惯会导致我们的开发的app存在内存泄露的情况。下面

zlgzh的博客 4011

Android内存优化————常见内存泄漏及优化方案(面试必问)

前言 最近在整理回顾零碎知识点,今天整理下Android内存优化方案分享给大家。 在Android开发中,一些不好的编程习惯会导致我们的开发的app存在内存泄露的情况。下面简单介绍一些在Android开发中常见的内存泄露场景及优化方案(面试必问)。    单例导致内存泄露 单例模式在Android开发中会经常用到,但是如果使用不当就会导致内存泄露。因为单例的静态特性使得它的生命周期同...

递归安卓 726

【安卓笔记】OOM与内存优化

简单介绍:1. OOM常见场景和解决方案。2. 内存分析命令的功能和使用。3. 内存分析工具MAT的功能和简单使用方法。

liosen的博客 1492

Android内存泄漏优化总结

Android内存泄漏优化总结什么是内存?Android中的内存是手机的RAM。主要包括如下几个部分: 1、寄存器 位于Cpu内部,速度最快。 2、栈 用于存放基本类型以及引用变量。 3、堆 主要用于存放数组和new出来的对象,它由垃圾回收器进行管理(GC)。对内存的优化也是处理的堆内存。 4、静态存储区 存储应用运行一直存在的数据(static变量) 5、常量池 存放定义的常

Coder_android 8504

SimplifyReader项目调试技巧与常见问题解决指南

SimplifyReader是一款基于Google Material Design设计开发的Android客户端,集成了新闻简读、图片浏览、视频播放、音乐收听和二维码扫描五大功能模块。作为采用MVP架构的开源项目,SimplifyReader为开发者提供了优秀的学习参考,但在实际使用和调试过程中可能会遇到一些技术挑战。本文将分享SimplifyReader项目的调试技巧和常见问题解决方案,帮助开发

gitblog_00858的博客 1149

android 内存优化-内存泄漏

内存泄漏在Android内存优化是一个比较重要的一个方面,很多时候程序中发生了内存泄漏我们不一定就能注意到,所有在编码的过程要养成良好的习惯。总结下来只要做到以下这几点就能避免大多数情况的内存泄漏:构造单例的时候尽量别用Activity的引用;静态引用时注意应用对象的置空或者少用静态引用;使用静态内部类+软引用代替非静态内部类;及时取消广播或者观察者注册;耗时任务、属性动画在Activity销毁时记得cancel;文件流、Cursor等资源及时关闭;

anhuilee的博客 1442

Android常见内存泄漏及优化的学习笔记

Android常见内存泄漏及优化的学习笔记 单例导致的内存泄漏 public class AppSettings { private static AppSettings sInstance; private Context mContext; private AppSettings(Context context) { // 错误代码 thi...

WJ的博客 238

Android内存优化系列

为什么要进行内存优化? 在android中,对内存的优化是一个app很重要的一个指标,内存优化的比较好的app用起来比较流畅而且出现崩溃的概率会大大降低。 虽然由于科技的发展,使得手机内存越来越高,但是由于引用版本更新迭代以及技术的革新,导致我们的app使用内存也越来越高。 一张图来描述微信各个版本所占用的系统内存: 常见程序程序所占用的内存: 如果内存无法妥善处理好,容易出现如下...

it_Y的博客 723

Android WebView常见问题及解决方案汇总

Android WebView常见问题及解决方案汇总

zhengxiuchen86的博客 349
上一篇: Synchronized修饰实例方法即非静态方法
下一篇: 几种常见的Java单例模式写法
倚窗为听雨
博客等级 码龄16年 6粉丝 11原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值