Android 性能优化之内存优化

文章目录

  • Android 性能优化之内存优化
    • 内存问题
      • 内存抖动
      • 内存泄露
      • 内存溢出
    • 检测工具
      • Memory Profiler
      • Memory Analyzer
      • LeakCanary
    • 内存管理机制
      • Java
      • Android
    • 解决
      • 内存抖动问题
        • 模拟问题代码
        • 使用Memory Profiler工具检测
        • 优化技巧
      • 内存泄露问题
        • 模拟问题代码
        • 使用LeakCanary工具检测
        • 优化技巧
      • Bitmap优化
        • Bitmap内存模型
        • 资源文件目录
        • 优化技巧
    • 源码下载

Android 性能优化之内存优化

内存问题

  • 内存抖动
  • 内存泄露
  • 内存溢出

内存抖动

内存抖动指的是在短时间内大量对象被创建和销毁,导致频繁的垃圾回收(Garbage Collection, GC)活动。这种频繁的GC活动会占用大量的CPU资源,可能导致应用程序的卡顿或性能下降。

表现:内存曲线呈锯齿状。

内存泄露

内存泄露是指应用程序持有了不再需要的对象的引用,导致这些对象无法被垃圾回收器回收,从而占用了本可以被释放的内存空间。随着时间的推移,内存泄露会导致可用内存越来越少,最终可能导致应用程序崩溃或性能下降。

内存溢出

内存溢出是指应用程序尝试分配更多的内存空间,但系统无法满足这个请求,因为已经没有足够的内存空间可供分配。这通常会导致应用程序抛出OutOfMemoryError异常。

检测工具

  • Memory Profiler
  • Memory Analyzer
  • LeakCanary

Memory Profiler

  • Memory Profiler 是 Android Studio自带的内存分析工具。
  • 实时图表展示程序内存使用情况。
  • 识别内存泄露、抖动等。
  • 提供捕获堆转储、强制GC以及跟踪内存分配的能力。

Memory Analyzer

  • 强大的 Java Heap 分析工具,查找内存泄露已经内存占用。
  • 生成整体报告、分析问题等。

LeakCanary

  • 自动内存泄露检测。
    • LeakCanary自动检测这些对象的泄露问题:Activity、Fragment、View、ViewModel、Service。
  • 官网:https://github.com/square/leakcanary

内存管理机制

Java

Java 内存结构:堆、虚拟机栈、方法区、程序计数器、本地方法栈。

Java 内存回收算法:

  • 标记-清除算法:
    1. 标记出所需要回收的对象
    2. 统一回收所有标记的对象。
  • 复制算法:
    1. 将内存划分为大小相等的两块。
    2. 一款内存用完后复制存活对象到另一块中。
  • 标记-整理算法:
    1. 标记过程与“标记-清除“算法一样。
    2. 存活对象往一端进行移动。
    3. 清除其余内存。
  • 分代收集算法:
    • 结合多种收集算法优势。
    • 新生代对象存活率低,使用复制算法。
    • 老年代对象存活率高,使用标记-整理算法。

标记-清除算法缺点:标记和清除效率不高,会产生大量不连续的内存碎片。

复制算法:实现简单,运行高效。缺点:浪费一半空间。

标记-整理算法:避免标记-清理导致的内存碎片,避免复制算法的空间浪费。

Android

Android内存弹性分配,分配值与最大值受具体设备影响。

Dalvik 回收算法和 ART 回收算法都是 Android 操作系统中用于内存管理的垃圾回收机制

Dalvik 回收算法:

  • 标记-清除算法。
  • 优点是实现简单。缺点是在标记和清除阶段都会暂停应用程序的执行,这会导致应用程序出现短暂的卡顿,影响用户体验。

Art 回收算法:

  • 压缩式垃圾回收(Compacting Garbage Collection)的算法。在标记-清除算法的基础上进行了改进,以减少垃圾回收过程中的暂停时间。
  • 并发标记:ART 引入了并发标记阶段,这意味着它可以与应用程序的执行同时进行。这减少了由于垃圾回收导致的暂停时间。
  • 清除和压缩:在清除阶段,ART 不仅清除未被标记的对象,还会压缩内存,这意味着它会将存活的对象移动到一起,减少内存碎片。这使得内存管理更高效,并减少了内存分配失败的可能性。
  • 自适应回收:ART 还引入了自适应回收的概念,这意味着它会根据应用程序的行为和内存使用模式自动调整垃圾回收的频率和方式。这使得 ART 可以更好地适应不同的应用程序需求。

LMK机制:

  • Low Memory Killer 机制。
  • 主要作用是在系统内存不足时,根据一定的优先级策略,结束一些后台进程,以释放内存,保证系统的稳定性和响应性。

解决

内存抖动问题

模拟问题代码
public class ShakeActivity extends AppCompatActivity {private static Handler mHandler = new Handler() {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);String str = "";for (int i = 0; i < 10000000; i++) {str += i;}mHandler.sendEmptyMessageDelayed(1, 30);}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_shake);}public void startClick(View view) {mHandler.sendEmptyMessage(1);}@Overrideprotected void onDestroy() {super.onDestroy();mHandler.removeCallbacksAndMessages(null);}
}
使用Memory Profiler工具检测

Memory Profiler 可以查看内存分配情况,点击“Record Java/Kotlin allocations"。

在这里插入图片描述

上面的含义:

  • Java:Java 或 Kotlin 代码分配的内存。
  • Native:C 或 C++ 代码分配的内存。
  • Graphics:图形缓冲区队列为向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。CPU共享的内存。
  • Stack:应用中的原生堆栈和 Java 堆栈使用的内存。这通常与您的应用运行多少线程有关。
  • 应用用于处理代码和资源(如 dex 字节码、经过优化或编译的 dex 代码、.so 库和字体)的内存。
  • 应用使用的系统不确定如何分类的内存。
  • 应用分配的 Java/Kotlin 对象数。此数字没有计入 C 或 C++ 中分配的对象。

下面的含义:

  • Allocations:通过 malloc()new 运算符分配的对象数量。
  • Deallocations:通过 free()delete 运算符解除分配的对象数量。
  • Allocations Size:选定时间段内所有分配的总大小,单位是字节。
  • Deallocations Size:选定时间段内释放内存的总大小,单位是字节。
  • Total Count:Allocations 减去 Deallocations 的结果。
  • Remaining Size:Allocations Size 减去 Deallocations Size 的结果。
  • Shallow Size:堆中所有实例的总大小,单位是字节。

上图分析:

在这里插入图片描述

这块地方 Allocations 和 Deallocations 的数值比较相近,同时 Shallow Size 比较大,说明可能频繁的创建和销毁对象。

在这里插入图片描述

点击后,可以查看调用栈信息,结合代码可以推测出 Handler 地方存在内存抖动问题。

优化技巧
  • 避免大量频繁创建和销毁对象。

内存泄露问题

模拟问题代码
public class CallbackManager {public static ArrayList<Callback> sCallbacks = new ArrayList<>();public static void addCallback(Callback callback) {sCallbacks.add(callback);}public static void removeCallback(Callback callback) {sCallbacks.remove(callback);}
}
public class LeakActivity extends AppCompatActivity implements Callback {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_leak);ImageView imageView = findViewById(R.id.imageView);Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.splash);imageView.setImageBitmap(bitmap);CallbackManager.addCallback(this);}@Overridepublic void onOperate() {}
}
使用LeakCanary工具检测

添加依赖库:

debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.14'

发生内存泄露后,LeakCanary会生成相关信息,并自动转储:

在这里插入图片描述

上图可知:是 LeakActivity 发生内存泄露了,并显示出引用链关系。

当然也可以生成 hprof 文件,通过 Profiler 工具查看具体信息:

在这里插入图片描述

上图可知:发生了10个泄露点,其中就有 LeakActivity,点击 LeakActivity 可以查看这内存泄露的对象,并查看引用链,可知是被ArrayList持有了。

优化技巧
  • 及时回收集合元素。
  • 避免static引用过多实例。
  • 使用静态内部类。
  • 及时关闭资源对象。

Bitmap优化

使用完Bitmap后若不释放图片资源,容易造成内存泄露,从而导致内存溢出

Bitmap内存模型
  • api10之前(Android2.3.3):Bitmap对象放在堆内存,像素数据放在本地内存。
  • api10之后:均在堆内存。
  • api26之后(Android8.0):像素数据放在本地内存。使得native层的Bitmap像素数据可以和Java层的对象一起快速释放。

内存回收:

  • 在Android 3.0之前,需要手动调用Bitmap.recycle()进行Bitmap的回收。
  • 从Android 3.0开始,系统提供了更智能的内存管理,大多数情况下不需要手动回收Bitmap。

Bitmap的像素配置:

Config占用字节大小(byte)说明
ALPHA_81单透明通道
RGB_5652简易RGB色调
ARGB_8888424位真彩色
RGBA_F168Android 8.0 新增(HDR)

计算Btimap占用内存:

  • Bitmap#getByteCount()
  • getWidth() * getHeight() * 1像素占用内存
资源文件目录

资源文件问题:

  • mdpi (中等密度):大约160dpi,1x资源。
  • hdpi (高密度):大约240dpi,1.5x资源。
  • xhdpi (超高密度):大约320dpi,2x资源。
  • xxhdpi (超超高密度):大约480dpi,3x资源。
  • xxxhdpi (超超超高密度):大约640dpi,4x资源。

测试代码:

private void printBitmap(Bitmap bitmap, String drawable) {String builder = drawable +" Bitmap占用内存:" +bitmap.getByteCount() +" width:" +bitmap.getWidth() +" height:" +bitmap.getHeight() +" 1像素占用大小:" +getByteBy1px(bitmap.getConfig());Log.e("TAG", builder);
}private int getByteBy1px(Bitmap.Config config) {if (Bitmap.Config.ALPHA_8.equals(config)) {return 1;} else if (Bitmap.Config.RGB_565.equals(config)) {return 2;} else if (Bitmap.Config.ARGB_8888.equals(config)) {return 4;}return 1;
}
// 逻辑密度
float density = metrics.density;
// 物理密度
int densityDpi = metrics.densityDpi;
Log.e("TAG", density + "-" + densityDpi);// 1倍图
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.splash1);
printBitmap(bitmap1, "drawable-mdpi");// 2倍图
Bitmap bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.splash2);
printBitmap(bitmap2, "drawable-xhdpi");// 3倍图
Bitmap bitmap3 = BitmapFactory.decodeResource(getResources(), R.drawable.splash3);
printBitmap(bitmap3, "drawable-xxhdpi");// 4倍图
Bitmap bitmap4 = BitmapFactory.decodeResource(getResources(), R.drawable.splash4);
printBitmap(bitmap4, "drawable-xxxhdpi");// drawable
Bitmap bitmap5 = BitmapFactory.decodeResource(getResources(), R.drawable.splash);
printBitmap(bitmap5, "drawable");
/*3.0-480drawable-mdpi Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4drawable-xhdpi Bitmap占用内存:9281844 width:1287 height:1803 1像素占用大小:4drawable-xxhdpi Bitmap占用内存:4125264 width:858 height:1202 1像素占用大小:4drawable-xxxhdpi Bitmap占用内存:2323552 width:644 height:902 1像素占用大小:4drawable Bitmap占用内存:37127376 width:2574 height:3606 1像素占用大小:4*/

说明:

在 mdpi 的设备上 1dp1px,在 xhdpi 的设备上 1dp2px,在 xxhdpi 的设备上 1dp==3px。

因此当前设备是 xxhdpi,因此同一张图片在 xxhdpi 资源下宽是858,在 mdpi 资源下会放大3倍宽是2574,在 xhdpi 资源下会放大1.5倍宽是1287。

优化技巧
  • 设置多套图片资源。
  • 选择合适的解码方式。
  • 设置图片缓存。

源码下载

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

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

相关文章

顺序结构 ( 四 ) —— 标准数据类型 【互三互三】

序 C语言提供了丰富的数据类型&#xff0c;本节介绍几种基本的数据类型&#xff1a;整型、实型、字符型。它们都是系统定义的简单数据类型&#xff0c;称为标准数据类型。 整型&#xff08;integer&#xff09; 在C语言中&#xff0c;整型类型标识符为int。根据整型变量的取值范…

开源大势所趋

一、开源项目的发展趋势 技术栈多样化与专业化&#xff1a;随着技术的不断进步&#xff0c;开源项目涵盖了从云计算、大数据、人工智能到区块链、物联网等各个领域&#xff0c;技术栈日益丰富和专业化。这种趋势使得开发者能够根据自己的需求选择最适合的技术工具&#xff0c;促…

dify-api的Dockerfile分析

一.dify-api的Dockerfile文件 dify-api的Dockerfile文件如下所示&#xff1a; # base image FROM python:3.10-slim-bookworm AS baseLABEL maintainer"takatostgmail.com"# install packages FROM base as packagesRUN apt-get update \&& apt-get install…

nginx安装配置视频频服务器-windows

编译安装nginx 1、安装perl 安装地址: https://strawberryperl.com&#xff0c;选择msi安装程序即可 2、安装sed for windows 下载地址&#xff1a;https://sourceforge.net/projects/gnuwin32/files/sed/&#xff0c;执行安装程序结束后&#xff0c;将安装包bin目录配置到…

【seo常见的问题】搜索引擎

1、让网站访问量提高的最好的方法是什么? 了解搜索引擎行为和搜索用户的行为&#xff0c;就是通过观察搜索引擎排名机制获得有效途径&#xff0c;提供效率&#xff0c;并且通过一些相关数据&#xff0c;了解到用户的搜索行为。 2、我要你把一个站的关键词排名排到首页&#x…

【Adobe】动作捕获和动画制作软件Character Animator

Adobe Character Animator 是一款由Adobe公司出品的动作捕获和动画制作软件&#xff0c;旨在帮助用户直观地制作2D&#xff08;二维&#xff09;人物动画、实时动画&#xff0c;并发布动画。这款软件功能强大、操作简单&#xff0c;非常适合动画制作者、直播主以及社交媒体内容…

【STM32 ARM】操作寄存器控制led

文章目录 前言GPIO操作方法led原理图设置时钟APB的概念 设置APB设置输出引脚设置引脚高低电平寄存器寻找寄存器地址 总结 前言 STM32是STMicroelectronics&#xff08;意法半导体&#xff09;公司的一款32位Flash微控制器产品&#xff0c;基于ARM Cortex™-M内核。STM32系列微…

Groovy vs Kotlin 在Gradle配置文件中的差异与选择

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

beyond Compare连接 openWrt 和 VsCode

连接步骤总结 1. 新建会话 -> 文件夹比较 2.点击浏览文件夹 3.在弹出页面 配置 ftp 3.1&#xff09;选中ftp 配置文件 3.2)选中ssh2 3.3)填写我们需要远端连接的主机信息 先点击连接并浏览 得到下方文件夹 弹出无效登录&#xff0c;说明需要密码 我们返回右键刚刚创建的新 …

C++ | Leetcode C++题解之第227题基本计算器II

题目&#xff1a; 题解&#xff1a; class Solution { public:int calculate(string s) {vector<int> stk;char preSign ;int num 0;int n s.length();for (int i 0; i < n; i) {if (isdigit(s[i])) {num num * 10 int(s[i] - 0);}if (!isdigit(s[i]) &&am…

【智能制造-14】机器视觉软件

CCD相机和COMS相机? CCD&#xff08;Charge-Coupled Device&#xff09;相机和CMOS&#xff08;Complementary Metal-Oxide-Semiconductor&#xff09;相机是两种常见的数字图像传感器技术&#xff0c;用于捕捉和处理图像。 CCD相机&#xff1a; CCD相机使用一种称为CCD的光电…

北方论丛期刊

《北方论丛》投稿指南 为适应学术期刊文献信息传播现代化的需要&#xff0c;全面提高期刊质量&#xff0c;扩大学术交流&#xff0c;根据《中国学术期刊(光盘版)检索与评价数据规范》《中国高等学校社会科学学报编排规范》以及其他国家标准和法规文件&#xff0c;并结合《北方论…

如何用webpack来优化前端性能?

Webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。它通过分析你的项目结构&#xff0c;找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言&#xff08;如SCSS, TypeScript等&#xff09;&#xff0c;并将其转换和打包为合适的格式供浏…

数据分析入门指南:表结构数据(三)

在数字化转型的浪潮中&#xff0c;表结构数据作为企业决策支持系统的核心要素&#xff0c;其重要性日益凸显。本文深入剖析了表结构数据的本质特征、高效处理策略&#xff0c;并探讨了其在现代商业智能环境中的广泛应用&#xff0c;旨在为数据分析师与决策者提供前沿洞察与实战…

人工智能算法工程师(中级)课程3-sklearn机器学习之数据处理与代码详解

大家好&#xff0c;我是微学AI,今天给大家分享一下人工智能算法工程师(中级)课程3-sklearn机器学习之数据处理与代码详解。 Sklearn&#xff08;Scikit-learn&#xff09;是一个基于Python的开源机器学习库&#xff0c;它提供了简单有效的数据挖掘和数据分析工具。Sklearn包含了…

华为HCIP Datacom H12-821 卷34

1.单选题 防火墙默认已经创建了一些安全区域,以下哪一个安全区域不是防火墙上默认存在的? A、Trust B、DMZ C、Internet D、Local 正确答案&#xff1a; C 解析&#xff1a; 防火墙默认情况下为我们提供了三个安全区域&#xff0c;分别是 Trust、DMZ和Untrust 2.判断题 …

电脑快捷键:提升效率的秘密武器

在现代社会中&#xff0c;电脑已经成为我们生活中不可或缺的工具。然而&#xff0c;要想充分利用电脑的功能&#xff0c;熟练掌握一些快捷键是必不可少的。本文将为您介绍一些常用的电脑快捷键&#xff0c;帮助您提高工作效率&#xff0c;节省宝贵的时间。 Windows 系统快捷键 …

【国产开源可视化引擎Meta2d.js】鹰眼地图

鹰眼地图 画布右下角弹出一个缩略导航地图&#xff0c;鼠标点击可以跳到指定位置。 在线体验&#xff1a; 乐吾乐2D可视化 示例&#xff1a; // 显示缩略地图 meta2d.showMap();// 关闭缩略地图 meta2d.hideMap();

树形结构的一种便捷实现方案

背景 在开发过程中经常需要把平铺的数据结构转为树形的数据结构&#xff0c;例如多级菜单、组织机构等。 实现方案有很多种。 1、可以使用递归查询&#xff0c;但是这样数据一多会导致频繁的多次查询数据库&#xff0c;产生很多额外的IO开销&#xff0c;总体的响应时间会比较…

【uniapp微信小程序】uniapp微信小程序——页面通信

uniapp微信小程序——页面通信 在开发微信小程序过程中&#xff0c;页面之间的通信是一个常见需求。在使用 uniapp 开发微信小程序时&#xff0c;我们可以采用多种方式实现页面之间的数据传递和状态共享。本文将详细介绍几种常见的实现方式&#xff0c;以供开发者参考。 1. 页…