Android | App内存优化 之 内存抖动解决实战

简介: Android | App内存优化 之 内存抖动解决实战
本文的精简总结在文首Pre文末小结以及解决技巧处!!!

Pre

  • 定义:内存频繁分配和回收导致内存不稳定
  • **明显特征:频繁GC、

Memory Profiler 内存分配图形曲线呈锯齿状
CPU ProfilerCall Chart 栏下 反复出现绿色条形**

  • 危害:导致卡顿、OOM

内存抖动导致OOM

  • **频繁创建对象,!!!!!

导致内存不足或者产生内存碎片!!!!!
内存碎片内存不连续,有 内存空洞
某两个正在使用的内存中间有一个间隔,
这个间隔虽然也被算在可用内存里面,
但实际上,因为它过小,
当我们申请内存的时候,经常是需要申请一定量的连续内存,
而这些碎片小内存不符合要求,是不能拿来使用的)**

  • 不连续的内存片无法被分配,可分配的内存不足,导致OOM;
  • 情况严重时会导致卡顿;随后可分配的内存减少,便可能导致OOM!!!

解决内存抖动实战

使用Memory Profile 排查处理

不同的工具,有自己适合的使用场景;

使用Memory Profile 初步排查

(后文中Memory Profile 简写成MP)

  • 图表直观,可以清晰地看到内存曲线;
开始编程
  • 布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/bt_memory"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="执行任务" />

</LinearLayout>
  • 对应的Activity文件:
/**
 * 模拟内存抖动的界面
 */
public class MemoryShakeActivity extends AppCompatActivity implements View.OnClickListener {

    @SuppressLint("HandlerLeak")
    private static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            // 创造内存抖动(编写耗内存的操作)
            for (int index = 0; index <= 100; index++){
                String arg[] = new String[100000];
            }
            mHandler.sendEmptyMessageDelayed(0,30);
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memory);
        findViewById(R.id.bt_memory).setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        mHandler.sendEmptyMessage(0);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
    }
}
  • 运行:
  • 点击按钮前,MP图平稳:
  • 点击按钮后,开始出现锯齿状(真机调试可能锯齿状不会很明显):小米5s Plus真机调试Google Nexus_5X调试

这个时候,便可以判断,程序已经发生了内存抖动;

  • 情况严重时会导致卡顿;随后可分配的内存减少,便可能导致OOM!!!
  • **这个时候我们便从MP图锯齿状图形

观察到内存抖动的现象了,
接下来要开始分析,
内存抖动真正发生位置,是在哪里;**

  • **真正的项目中,一个Activity可能是有成百上千行代码,

那我们改如何知道哪里出了问题呢;**

  • 可以使用MP的堆转储按钮,继续进行分析:

**点击堆转储按钮,(或者直接在图中选中一段图形)
工具会弹出刚刚选中的一段时间内,
内存分配情况窗口
阅读时,可以点击下侧表格右上角的栏目项
进行对应项的排序,
如点击Allocations
分配情况表格会按照分配的实例个数进行排列:
我们可以看到锯齿的位置,String[]的分配是相对比较大的;
Shallow Size是该类型实例的总大小(以字节为单位);**

  • **于是现在可以锁定,String[]是最可疑的引起内存抖动的原因,

点击左边的String[]行项,工具会在右边,弹出另外一个窗口,
窗口上边是分配出来的该类型的所有实例(<工具右上>),
点击任意一个实例,
又会在下边弹出一个该实例的内存分配的堆栈信息<工具右下>——Allocation Call Stack),
信息即,这个实例占有的这块内存,是在哪里分配的:
我们可以看到,
MP工具的右下表格显示出来了右上角选中的对应的实例
分配内存的位置——
handlerMessage方法中,MemoryShakeActivity文件的第27行”;
右键之,选中Jump to Source
直接在IDE代码编辑界面,跳转追踪到,可疑诱因String[]创建源码处 / 位置!!
然后便发现原因,进行代码的修改!!**

或者也可以使用CPU Profiler 排查处理

**Call Chart 标签提供函数跟踪的图形表示形式,
其中,水平轴表示函数耗费的时间,垂直轴显示其被调用者。
对系统 API 的函数调用显示为橙色
应用自有函数调用显示为绿色
对第三方 API(包括 Java 语言 API)的函数调用显示为蓝色。**


参考文章:

  • **运行程序以及MP工具,

使用Record按钮开始记录某一段CPU执行的时间,
接着点击Stop停止对这段时间记录;
(上述Record记录完毕之后会在工具下侧弹出图表界面,
Call Chart ,依据这些图表数据)
跟踪这一段CPU执行的时间,
如果发现某一段(应用自有函数调用代码(即绿色的条形段)在反复地被执行,!!!!
(如下图的箭头所示)便是内存抖动的位置:!!!!
双击Call Chart中的一段绿色条形
可以直接在IDE代码编辑界面,跳转追踪到,可疑诱因String[]分配执行函数 源码处 / 位置!!
然后便发现原因,进行代码的修改!!**




小结

  • 使用Memory Profile 初步排查

该工具的图表显示方式非常直观,可以清楚地看到内存的使用情况;
可以很方便地发现 APP在使用过程中,
内存分配图形是不是一个锯齿状,有没有内存抖动的表现!

  • **使用Memory Profiler的堆转储 / 跟踪分配内存 功能

借助Instance View
追踪到分配内存较高/分配实例较多的实例类型
跟踪该实例类型的某几个具体实例 创建/分配 位置

(或者使用CPU Profiler,跟踪一段CPU执行的时间,
如果发现某一段应用自有函数调用代码
Call Chart 栏下的绿色条形反复地被执行,便是内存抖动的位置,
追踪这些绿色条形重复执行可疑函数位置),

然后结合代码进行排查,找到诱因位置;**




内存抖动的解决技巧

**重点关注:循环或者频繁调用的地方!!
因为内存抖动就是 内存在被不断地回收分配
这种情况的话经常是 出现在 循环或者频繁调用的地方**





参考自
相关文章
|
4天前
|
缓存 数据处理 Android开发
Android经典实战之Kotlin常用的 Flow 操作符
本文介绍 Kotlin 中 `Flow` 的多种实用操作符,包括转换、过滤、聚合等,通过简洁易懂的例子展示了每个操作符的功能,如 `map`、`filter` 和 `fold` 等,帮助开发者更好地理解和运用 `Flow` 来处理异步数据流。
33 4
|
4天前
|
API Android开发 开发者
Android经典实战之使用ViewCompat来处理View兼容性问题
本文介绍Android中的`ViewCompat`工具类,它是AndroidX库核心部分的重要兼容性组件,确保在不同Android版本间处理视图的一致性。文章列举了设置透明度、旋转、缩放、平移等功能,并提供了背景色、动画及用户交互等实用示例。通过`ViewCompat`,开发者可轻松实现跨版本视图操作,增强应用兼容性。
24 5
|
1天前
|
Linux Android开发 iOS开发
Android经典实战之Kotlin Multiplatform跨平台开发
KMP(Kotlin Multiplatform)是由JetBrains开发的开源技术,让开发者能在多平台间高效重用代码,保留原生编程优势。适用于Android/iOS应用、多平台库及桌面应用开发。KMP支持代码共享、预期与实际声明机制,具备灵活性、稳定性和性能优势。通过Compose Multiplatform可实现跨平台UI共享。开发者可访问官方文档开始学习。
7 1
|
1天前
|
编译器 API Android开发
Android经典实战之Kotlin Multiplatform 中,如何处理不同平台的 API 调用
本文介绍Kotlin Multiplatform (KMP) 中使用 `expect` 和 `actual` 关键字处理多平台API调用的方法。通过共通代码集定义预期API,各平台提供具体实现,编译器确保正确匹配,支持依赖注入、枚举类处理等,实现跨平台代码重用与原生性能。附带示例展示如何定义跨平台函数与类。
6 0
|
3天前
|
编译器 Android开发 开发者
Android经典实战之Kotlin 2.0 迁移指南:全方位优化与新特性解析
本文首发于公众号“AntDream”。Kotlin 2.0 已经到来,带来了 K2 编译器、多平台项目支持、智能转换等重大改进。本文提供全面迁移指南,涵盖编译器升级、多平台配置、Jetpack Compose 整合、性能优化等多个方面,帮助开发者顺利过渡到 Kotlin 2.0,开启高效开发新时代。
6 0
|
5天前
|
XML 数据可视化 API
Android经典实战之约束布局ConstraintLayout的实用技巧和经验
ConstraintLayout是Android中一款强大的布局管理器,它通过视图间的约束轻松创建复杂灵活的界面。相较于传统布局,它提供更高灵活性与性能。基本用法涉及XML定义约束,如视图与父布局对齐。此外,它支持百分比尺寸、偏移量控制等高级功能,并配有ConstraintSet和编辑器辅助设计。合理运用可显著提高布局效率及性能。
16 0
|
6天前
|
API 调度 Android开发
Android经典实战之处理后台任务的2个工具
本文介绍Android后台任务管理,涵盖WorkManager与JobScheduler的使用方法及区别。WorkManager属Jetpack库,确保任务可靠执行,支持延迟与条件依赖。JobScheduler则针对特定条件下的任务调度,如网络类型。两者各有优势,WorkManager适用于多数场景。
11 0
|
2天前
|
JavaScript 前端开发 Java
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
IT寒冬使APP开发门槛提升,安卓程序员需转型。选项包括:深化Android开发,跟进Google新技术如Kotlin、Jetpack、Flutter及Compose;研究Android底层框架,掌握AOSP;转型Java后端开发,学习Spring Boot等框架;拓展大前端技能,掌握JavaScript、Node.js、Vue.js及特定框架如微信小程序、HarmonyOS;或转向C/C++底层开发,通过音视频项目如FFmpeg积累经验。每条路径都有相应的书籍和技术栈推荐,助你顺利过渡。
13 3
FFmpeg开发笔记(四十七)寒冬下安卓程序员的几个技术转型发展方向
|
6天前
|
Java Android开发 iOS开发
探索安卓与iOS开发的差异:平台选择对项目成功的影响
在移动应用开发的世界中,选择正确的平台是关键。本文通过比较安卓和iOS开发的核心差异,揭示平台选择如何影响应用的性能、用户体验和市场覆盖。我们将深入探讨各自的开发环境、编程语言、用户界面设计原则以及发布流程,以帮助开发者和企业做出明智的决策。
27 9
|
1天前
|
搜索推荐 Android开发 iOS开发
探索安卓与iOS开发的差异性与互补性
【8月更文挑战第19天】在移动应用开发的广阔天地中,安卓与iOS两大平台各据一方,引领着行业的潮流。本文将深入探讨这两个平台在开发过程中的不同之处以及它们之间的互补关系,旨在为开发者提供一个全面的视角,帮助他们更好地把握市场动态,优化开发策略。通过分析各自的开发环境、编程语言、用户界面设计、性能考量及市场分布等方面,我们将揭示安卓与iOS开发的独特魅力和挑战,同时指出如何在这两者之间找到平衡点,实现跨平台的成功。