Android 性能优化(二):LeakCanary【用于分析代码是否存在内存泄漏】程序无响应

目录

1)内存相关的五种常见问题
2)内存溢出和内存泄漏
3)LeakCanary是什么?
4)LeakCanary如何使用,如何分析?
5)LeakCanary监测的内容

提问:程序有时候很卡,经常会出现闪退,出现程序无响应,在项目过程中遇到主要的问题我们应该如何解决呢?这篇文章会介绍LeakCanary工具来分析和解决这些问题。

一、内存相关的五种常见问题

OOM(Out of Memory)是指内存不足,即应用程序在运行过程中申请的内存超过了系统可用的内存资源。当系统检测到内存不足时,会触发 OOM 错误并终止应用程序的运行。

OOM 通常发生在应用程序加载大量图片、缓存数据、创建大对象等场景下。如果应用程序没有有效地管理内存,持续申请内存而不释放,就容易导致内存溢出,最终触发 OOM 错误。

在这里插入图片描述为什么明明还有4M的内存空间,加载1M的图片是,会报OOM呢,因为内存空间不连续。
在这里插入图片描述

二、内存溢出和内存泄漏

内存溢出指的是应用程序在运行过程中申请的内存超过了系统可用的内存资源。当系统检测到内不足时,会触发 Out of Memory(OOM)错误并终止应用程序的运行。内存溢出通常是由于应用程序持续申请内存而没有及释放导致的,最终导致系统无法为应用程序提供足够的内存空间。

内存泄漏指的是应用程序在使用完某些对象后,没有正确地释放对这些对象的引用导致这些对象无法被垃圾回收器回收,从而占用了系统的内存资源。随着时间的推移,内存泄漏累积起来,最终导致可用内存逐渐减少,可能触发 OOM 错误或导致应用程序变得缓慢、不稳定。

80%的原因都是因为内存泄漏导致内存溢出。

2.1 常见的内存泄漏

  1. 单例造成的内存泄露
  2. 非静态内部类创建静态实例造成的內存泄露
  3. Handler造成的内存泄露
  4. 线程造成的内存泄露

(1)为什么单例会造成内存泄漏?

在这里插入图片描述

(2)非静态内部类创建静态实例造成的內存泄露

public class OuterClass {static SomeListener listener;public void createLeak() {// 创建非静态内部类的实例并将其赋值给静态变量listener = new InnerClass();}private class InnerClass implements SomeListener {// 实现一些监听器的方法}
}

OuterClass 是外部类,InnerClass是非静态内部类。当调用createLeak()方法时,会创建InnerClass的实例并将其赋值给静态变量listener。由于 InnerClass是非静态内部类,它隐式地持有对外部类OuterClass引用。因此,即使 createLeak() 方法执行完毕后,InnerClass` 的实例仍然存在,并且无法被垃圾回收,导致内存泄漏。

为了解决这个问题,内部类改为静态内部类:将 InnerClass 改为静态内部类,这样它就不再隐式地持有外部类的引用

public class OuterClass {private static SomeListener listener;public void createLeak() {// 创建静态内部类的实例并将其赋值给静态变量listener = new InnerClass();}private static class InnerClass implements SomeListener {// 实现一些监听器的方法}
}

(3)Handler造成的内存泄漏

public class MainActivity extends AppCompatActivity {private static final int_CODE = 1;private Handler mHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建 Handler 实例,并在 handleMessage() 方法中mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {if (msg.what == MESSAGE_CODE) {// 处理消息。这里可能会发生内存泄漏,因为发送的延迟消息。}}};// 发送延迟消息mHandler.sendEmptyMessageDelayed(MESSAGE_CODE, 1000);}@Overrideprotected void onDestroy() {super.onDestroy();// 方法一:移除所有未处理的消息和回调,避免内存泄漏mHandler.removeCallbacksAndMessages(null);}
}
方法二可以使用弱引用来避免Handler持有对外部类的引用import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;public class MyActivity extends Activity {private static class MyHandler extends Handler {private WeakReference<MyActivity> mActivityRef;public MyHandler(MyActivity activity) {mActivityRef = new WeakReference<>(activity);}@Overridepublic void handleMessage(Message msg) {MyActivity activity = mActivityRef.get();if (activity != null) {// 处理消息}}}private MyHandler mHandler;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mHandler = new MyHandler(this);// 发送延迟消息mHandler.sendEmptyMessageDelayed(1, 1000);}@Overrideprotected void onDestroy() {super.onDestroy();// 移除所有未处理的消息和回调mHandler.removeCallbacksAndMessages(null);}
}

(4)线程

public class MainActivity extends AppCompatActivity {private Thread mThread;@Override    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 创建一个线程并启动mThread = new Thread(new Runnable() {@Overridepublic void run() {// 模拟耗时操作try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}});mThread.start();}@Overrideprotected void onDestroy() {super.onDestroy();// 销毁Activity时,没有正确停止线程,导致线程持有Activity的引用而无法被回收,造成内存泄露}
}
public class MainActivity extends AppCompatActivity {private Handler mHandler;private Runnable mRunnable;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mHandler = new Handler();mRunnable = new Runnable() {@Overridepublic void run() {// 模拟耗时操作try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}};mHandler.post(mRunnable);}@Overrideprotected void onDestroy() {super.onDestroy();// 停止线程mHandler.removeCallbacks(mRunnable);}
}

可以看到种类还是比较多,如果我们想完全去避免,还是比较难的,可能一不小心,就会写错了,所以我们要介绍一下今天的主角"LeakCanary"。

三、LeakCanary是什么?

LeakCanary是一个用于检测Android应用中内存泄漏的开源库。它由Square公司开发并维护,旨在帮助开发者及时发现和修复应用中的内存泄漏问题。

四、LeakCanary如何使用,如何分析?

(1)引入依赖
在这里插入图片描述(2)运行debug

  1. 当出现内存溢出的时候会提示这个。
    在这里插入图片描述
    然后我们就可以根据代码进行分析。
    在这里插入图片描述

为什么没有位置显示呢?如何去分析呢?这个其实可以定位到类,定位到某个变量,可能有的人看到这个信息就会很懵,但是学过我们”内存泄漏的常见几种情况“后,那么我们就可以进行分析优化。

五、LeakCanary监测的内容

LeakCanary是一个用于检Android应用程序中内存泄漏的工具。它能够监测和报告以下内容:

  1. 活动泄漏:当一个Activity被销毁后,仍然存在对的引用,导致无法被垃圾回收。

  2. Fragment泄漏:当一个Fragment被销毁后,仍然存在对它的引用,导致无法被垃圾回收。

  3. 对话框泄漏:当对话框被关闭后,仍然存在对它的引用,导致无法被垃圾回收。

  4. 广播接收器泄漏:当一个广播接收器未被正确注销,导致持续接收广播,从而引起内存泄漏。

  5. 单例对象泄漏:当一个单例对象中持有对Activity或Fragment的引用,导致无法释放这些对象。

  6. 视图泄漏:当一个视图对象被销毁后,仍然存在对它的引用,导致无法被垃圾回收。

当LeakCanary检测到以上情况时,它会生成一个详细的报告,包含泄漏对象的类型、引用链、及内存泄漏的原因等信息,以帮助开发者定位和修复内存泄漏问题。

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

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

相关文章

前端开发:Vue2.0桌面组件库-Element

引入Element的步骤&#xff1a; 1.在vscode终端中执行命令&#xff08;需要联网&#xff09; 下载成功 2.在main.js中导入element.ui组件库。 同上&#xff0c;自定义的组件需要先在根组件中引入。 3.访问官网&#xff0c;复制调整代码

变阻器的主要特性和参数有哪些?

变阻器的主要特性和参数有很多&#xff0c;下面将详细介绍几个重要的特性和参数&#xff1a; 1. 电阻范围&#xff1a;滑动变阻器的电阻范围是指其最大电阻值和最小电阻值之间的范围&#xff0c;这个范围通常由制造商指定&#xff0c;用户在选择变阻器时需要根据实际需求选择合…

基于 SSM 的汽车租赁系统

基于 SSM 的电器网上订购系统 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;Spring、JSP、MyBatis 工具&#xff1a;MyEclipse/IDEA、Tomcat 引言 汽车租赁是在约定时间内&#xff0c;租赁经营人将租赁汽车&#xff08;包括载货汽车和载客汽车&#x…

AFSim 仿真系统--子系统几何考虑

子系统几何考虑 概述 由于WSF试图表示以多种方式运行的子系统&#xff08;传感器&#xff0c;武器或通信&#xff09;&#xff0c;因此它提供的定义属性的机制&#xff0c;如几何限制&#xff0c;可能相当令人生畏。本文档提供了关于这些机制如何运作以及如何定义行为类似于真实…

Axure RP:打造动态交互的大屏可视化设计利器

Axure大屏可视化是指使用Axure RP这款原型设计工具来创建具有视觉冲击力和数据展示功能的大屏幕界面。Axure以其强大的交互设计和丰富的组件库&#xff0c;成为了实现大屏可视化的重要工具之一。以下是对Axure大屏可视化的详细阐述&#xff1a; 一、Axure在大屏可视化中的优势 …

ctfshow web入门 中期测评 web503--web516(无web511--web514)

web503 看了之前的文件的发现都没办法利用了 这个页面的源码发现了 layui.use([layer, form], function(){var layer layui.layer,form layui.form;form.on(submit(admin_settings), function(data){$.ajax({url:api/admin_settings.php,dataType:"json",type:po…

STM32项目分享:智能台灯(机智云)系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 PCB图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.com/video/BV1My411q7fE…

小白学大模型:LLaMA-Factory 介绍与使用

最近这一两周看到不少互联网公司都已经开始秋招提前批了。 不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友…

基于CentOS Stream 9平台安装MySQL Community Server 9.0.1 Innovation

1. 安装之前 1.1 查看系统版本 cat /etc/redhat-releaseCentOS Stream release 9 1.2 查看cpu架构 lscpu架构&#xff1a; x86_64 CPU 运行模式&#xff1a; 32-bit, 64-bit 2. 官网下载 https://dev.mysql.com/downloads/mysql/ 要多看看 官方9.0文档&#xff1a;https://d…

NSL-KDD入侵检测系统的设计与实现系列预告

每日进阶-基于机器学习的入侵检测系统——打怪升级之道 在当今的数字时代&#xff0c;网络安全不仅是防御&#xff0c;更是主动出击。你是否想知道如何用机器学习技术设计一套入侵检测系统&#xff08;IDS&#xff09;&#xff0c;让黑客无所遁形&#xff1f;本系列文章将为您揭…

unity2D游戏开发12单例

单例 我们先了解一种被称为单例的软件设计模式。当应用程序需要在生命周期内创建特定类的单个实例时,可以使用单例。当一个类提供了游戏中其他几个类使用的功能时,单例会很有用,例如,在Game Manager 类中协调游戏逻辑,单例可以提供对该类及其功能的公共统一访问入口。单例…

入门 PyQt6 看过来(案例)14~ 分组

本文分享一个分组框功能&#xff0c;采用pyqt6里的QGroupBox​控件&#xff0c;效果如下&#xff1a;性别和专业分开为两个分组框内&#xff1a; ​ 1 功能实现思路 ui页面布局设计 性别和专业要设计成两个分组框&#xff1a; ​ 逻辑实现 引入信号和槽函数来实现点击单选…

搞懂数据结构与Java实现

文章链接&#xff1a;搞懂数据结构与Java实现 (qq.com) 代码链接&#xff1a; Java实现数组模拟循环队列代码 (qq.com) Java实现数组模拟栈代码 (qq.com) Java实现链表代码 (qq.com) Java实现哈希表代码 (qq.com) Java实现二叉树代码 (qq.com) Java实现图代码 (qq.com)

从区块链到股票市场的全方位布局,广辉团队创新引领共创财富未来!

广辉团队作为一家涉足互联网投资领域的团队&#xff0c;在短短几年内迅速崛起&#xff0c;成为行业中的佼佼者。这支团队汇聚了来自各行各业的商业精英&#xff0c;并在互联网金融领域创造了巨大的财富。业务范畴涵盖了资产管理、资本市场、消费金融、保险市场、零售银行及财富…

UDP通信 单播,广播,组播

UDP通信实现 #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); - 参数&#xff1a; struct sockaddr *src_addr, socklen_t *addrlen…

数据库期末复习

数据库期末复习 分析题 1 &#xff08;1&#xff09;使用数据库系统可以大大提高应用开发的效率&#xff0c;方便用户的使用减轻数据库系统管理人员维护的负担&#xff0c;请回答数据库系统有哪些部分组成&#xff1f;什么是数据库管理系统&#xff0c;其主要功能包括哪些方而&…

vue3项目报错集合

目录 一、does not provide an export named default 一、does not provide an export named default 报错截图&#xff1a; 原因&#xff1a; vite对commonjs兼容性太差&#xff0c;导致无法引入jsoneditor&#xff0c;可以使用originjs/vite-plugin-commonjs插件解决。&am…

Cocos Creator2D游戏开发(7)-飞机大战(5)-让子弹飞

飞机大战(5)-碰撞及积分 参考敌机的生成 子弹由飞机生成,放在player_node节点子弹重复使用,要使用预制体;子弹新增了动画 ①创建一个预制体 命名为playerBullet_prefab ② 双击预制体将bullet1图片拖入预制体 保存,关闭(场景编辑器里面的) ③ 发射子弹 player加入代码 prop…

【网络安全】破解邀请码实现未经授权的访问和账户接管

未经许可&#xff0c;不得转载。 文章目录 前言1、邀请用户2、低级账户访问3、提取用户 ID 和 OTP4、准备字典5、攻击6、账户接管 前言 ExampleSpark&#xff08;化名&#xff09;是一个专为团队管理和项目协作而设计的强大平台。它提供了用于管理用户、项目和权限的综合工具。…

【华视电子CVR100A】 身份证读取与酒店收银系统源码整合:CyberWinApp-SAAS 本地化及未来之窗行业应用跨平台架构

一、酒店系统连接身份证阅读器好处 在开房界面&#xff0c;点击读取身份证&#xff0c;可以自动读取姓名&#xff0c;性别&#xff0c;地址&#xff0c;身份证号码 1. 提高办理入住效率 - 传统的手动输入身份证信息繁琐且容易出错&#xff0c;一键读取能够快速准确地获取客人身…