Android 性能优化之黑科技开道(二)

3. 其它可以黑科技优化的方向

3.1 核心线程绑定大核

3.1.1 定义

核心线程绑定大核的思路也很容易理解,现在的 CPU 都是多核的,大核的频率比小核要高不少,如果我们的核心线程固定运行在大核上,那么应用性能自然会有所提升。

核心线程指的是 UI 线程、RenderThread 线程,因为它们直观影响用户的感受,或者在具体项目中的其它特定线程,比如语音处理,为了有更快的处理结果,语音线程也是可以列为核心线程的。

3.1.2 查看设备是否有大小核

1. 可以通过/sys/devices/system/cpu/目录下的文件获取各个核的频率

2. 尝试了下正在开发的设备,它没有大小核之分,所有核的频率全都一样,如下:

3. 当然,我们可以将此判断写到代码中,由我们的 App 智能判断是否需要绑定大小核,并找出来大核线程是哪个,具体代码这里就不贴了,原理同上,需要注意下读取权限问题

3.1.3 绑定 CPU 核实现

1. 绑定大核是通过函数 sched_setaffinity 实现的。

extern "C" JNIEXPORT void JNICALL Java_com_zj_android_startup_optimize_StartupNativeLib_bindCore(JNIEnv env, *jobject /* this */, jint thread_id, jint core) {
    cpu_set_t mask;     // CPU  核的集合
    CPU_ZERO(&mask);    // 将mask置空
    CPU_SET(core, &mask);    // 将需要绑定的  cpu  核设置给mask,核为序列0,1,2,3……
    if (sched_setaffinity(thread_id, sizeof(mask), &mask) == -1) { // 将线程绑核
        LOG  ("bind thread %d to core %d fail", thread_id, core);
    } else {
        LOG  ("bind thread %d to core %d success", thread_id, core);
    }
}

2. 如上所示,sched_setaffinity 共有 3 个参数。

  • 参数 1 是线程的 id,如果为 0 则表示主线程。
  • 参数 2 表示 cpu 序列掩码的长度。
  • 参数 3 则表示需要绑定的 cpu 序列的掩码。

3. 以上是线程绑定大核的核心代码,可以看到我们还需要获取 RenderThread 的 id ,以及 cpu 大核的序列。

4. 应用中线程的信息记录在 /proc/pid/task 的文件中,通过解析 task 文件就可以获取当前进程的所有线程,而 cpu 大核序列也可以通过解析 /sys/devices/system/cpu 目录实现。

3.2 GC 抑制

3.2.1 什么是 GC 抑制

  1. 首先 GC,就是 Java 的垃圾回收,GC 抑制指的是在 App 启动阶段,不让系统做 GC 或者是将 GC 的频繁降低,以提高启动速度

  2. 此技术在 Android10 以上的系统已加入,所以这里讨论的是 在 Android10 以下的系统中添加此功能

3.2.2 Android10 中的 GC 抑制如何实现的

1. Java 的垃圾回收机制,在 Android 5.0 之后,ART 取代了 Dalvik,ART 虚拟机在垃圾回收的时候虽然没有像 Dalvik 一样 stop the world,但在启动阶段如果发生垃圾回收,GC 线程同样抢占了不少系统资源。

2. Google 也注意到启动阶段 GC 对启动速度的影响,并在 Android 10 之后做了一定的优化,详情可见如下提交:https://cs.android.com/android/_/android/platform/art/+/a98a28262f645d100e2dee9587e7822d35ade6f9 

3. 可以看出,基本思路是在 2s 内提高后台 GC 的阈值,减少启动阶段的 GC 次数,根据 Google 的测试,抑制 GC 后效果如下:

4. 可以看出,GC 次数明显减少,启动速度也有一定的提升。

3.2.3 我们的程序是否有必要进行 GC 抑制

1. 可以通过以下代码获取 gc 的次数与耗时,方便统计 gc 对启动耗时的影响,以评估是否有必要做 GC 抑制

Debug.getRuntimeStat("art.gc.gc-count") // gc 次数
Debug.getRuntimeStat("art.gc.gc-time")  // gc 耗时
Debug.getRuntimeStat("art.gc.blocking-gc-count") // 阻塞 gc 次数
Debug.getRuntimeStat("art.gc.blocking-gc-time") // 阻塞 gc 耗时 

在电视项目的首页查看 GC 的情况,结果如下,发现从启动到首页显示出来,GC 次数和时间都是比较高的值:

2. 另外,我在 profiler 工具中观察到我们的 GC 线程可以更直观的看到,不只是在启动的时候,后续它也会频繁大量的运行,如下:

3.2.4 GC 抑制实现

GC 工作的原理

GC 主要是通过 HeapTaskDaemon 线程实现的,这是一个守护线程,在 Zygote 线程启动后这个线程也就启动了,启动后主要做了以下工作:

  1. 从 HeapTaskDaemon.runInternal()方法开始一步步调用到 native 层的 task_processor.RunAllTasks() 方法。

  2. 当 TaskProcessor 中的 tasks 为空时,会休眠等待,否则会取出第一个 HeapTask 并执行其 Run 方法。

    而 HeapTask 的 Run 方法是一个虚函数,需要子类来实现。

class HeapTask : public SelfDeletingTask {
};
 
class SelfDeletingTask : public Task {
};
 
class Task : public Closure {
};
 
class Closure {
 public:
  virtual ~Closure() { }
  // 定义 Run 虚函数
  virtual void Run(Thread* self) = 0;
};

HeapTask 就是垃圾回收的任务,有多个子类,比如最常见的 ConcurrentGCTask 就是其子类,在 Java 内存达到阈值时就会执行这个 Task,用于执行并发 GC。

GC 抑制方案:Native 层的 Hook

在了解了 HeapTaskDaemon 的执行流程之后,我们想到,如果启动时在 ConcurrentGCTask 的 Run 方法执行前休眠一段时间,不就可以实现 GC 抑制了吗?

而 Run 方法正好是虚函数,虚函数与 Java 中的抽象函数类似,留给子类去扩展实现多态。

虚函数和外部库函数一样都没法直接执行,需要在表中去查找函数的真实地址,那么我们是不是可以使用类似 PLT Hook 的思路,使用自定义函数的地址替换原有函数地址,实现 Hook 呢?

答案是肯定的,如上图所示,一个类中如果存在虚函数,那么编译器就会为这个类生成一张虚函数表,并且将虚函数表的地址放在对象实例的首地址的内存中。同一个类的不同实例,共用一张虚函数表的。

因此我们的主要思路如下:

  1. 启动时将虚函数表中的 Run 函数地址替换为自定义函数地址。

  2. 在自定义函数内部休眠一段时间,抑制 GC。

休眠完成后将虚函数表中的函数地址替换回来,避免影响后续执行。

3.3 字节码插桩与性能监控

3.3.1 性能监控的流程

基于性能问题,我们可以进行一个性能方面的监控,以达到随时了解情况,随时进行优化的目的。市场上有很多商业化的 APM 平台,比如著名的 NewRelic,还有国内的 听云、OneAPM 等等,还有我们自己也有性能监控平台。这些平台的工作流程如下:

  1. 首先在客户端(Android、iOS、Web 等)采集数据;

  2. 接着将采集到的数据整理上报到服务器;

  3. 服务器接收到数据后建模、存储、挖掘分析,让后将数据可视化,供用户使用。

其中客户端数据采集时使用字节码插桩比较方便快捷,并且具有较大的通用性

3.3.2 字节码插桩原理

字节码插桩的原理就是在 Android 打包的时候,通过 ASM 等框架将 Java 字节码,插入到特定位置上,达到自动加入某些重复代码的目的,也即是 AOP 编程,如下是 Android 打包的流程:

插桩入口

在打包过程中,会将所有 class 文件,包括第三方的 class 文件打包成一个或者多个 dex 文件。这其中涉及到两个很关键的环节:

javac:将 。java 格式的源代码文件编译成 class 文件;

dex: 将 class 格式的文件打包汇总,组成一个或者多个 dex 文件。

我们想要对字节码进行修改,只需要在 javac 之后 dex 之前遍历所有的字节码文件,并按照一定的规则过滤修改就好了,这里便是字节码插桩的入口。

那么我们到底如何介入打包过程,在 class 转换为 dex 文件的时候实现对字节码的修改呢?

答案是 transform api。Android Gradle Plugin 1.5.0 及以上版本,Google 官方提供了 transform api 作为字节码插桩的入口。我们只需要实现一个自定义的 Gradle Plugin,然后在编译阶段去修改字节码文件即可。

修改字节码

找到了插桩入口,接下来就要对字节码进行修改。对于字节码的修改,比较常用的框架有 Javassist 和 ASM。具体的使用就不进行介绍了,有框架使用的话,写字节码还是比较方便的。

4. 总结

本篇主要介绍了一些 Android 中实用的黑科技,包括 Hook 技术,线程自定义调整,GC 抑制,字节码插桩等,在电视版智家 App9.0 项目中已经验证了部分技术,还有一些技术正在规划中,后续将会逐步的提升我们的 App 性能。

最后,讨论一个问题,这些黑科技是"奇淫巧技"吗,还是合理合法的使用呢?

这里引用一篇文章中的原话:

国产定制安卓系统一直都在安卓版本号更新之前,领先不只一个身位。

以至于每次的安卓大版本更新像是在追授国产定制 Android 在 N 年前魔改的功勋,甚至像是在若干个发行版本选一个最好的方案作为整个 Android 生态的标准。

招安,才是最形象的解释。

参考:如何评价谷歌刚发布的 AOSP14,在 iOS 和鸿蒙的竞争下,安卓还有哪些第三方开发的系统亮点值得关注?

国内的 Android 黑科技一直是率先发展的,遍数国内 Android 技术圈走过的路程,从之前的插件化,到双开等,哪一个在当时不算是"奇淫巧技"呢,最后不都成了 Android 官方的标配了么,所以,大胆的探索去吧,能解决我们问题的技术就是好技术。

5. 参考

  1. 盘点 Android 常用 Hook 技术

  2. 如何优雅关闭 Android 日志输出

  3. Android 中如何 Hook 住 JNI 方法

  4. JNI 函数 Hook 实战

  5. 启动优化中的一些黑科技,了解一下~

  6. Android 性能监控系列一(原理篇)

  7. 如何评价谷歌刚发布的 AOSP14,在 iOS 和鸿蒙的竞争下,安卓还有哪些第三方开发的系统亮点值得关注?

6. 团队介绍

三翼鸟数字化技术平台-场景设计交互平台」主要负责设计工具的研发,包括营销设计工具、家电VR设计和展示、水电暖通前置设计能力,研发并沉淀素材库,构建家居家装素材库,集成户型库、全品类产品库、设计方案库、生产工艺模型,打造基于户型和风格的AI设计能力,快速生成算量和报价;同时研发了门店设计师中心和项目中心,包括设计师管理能力和项目经理管理能力。实现了场景全生命周期管理,同时为水,空气,厨房等产业提供商机管理工具,从而实现了以场景贯穿的B端C端全流程系统。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++相关概念和易错语法(8)(匿名对象、构造+拷贝构造优化、构造析构顺序)

1.匿名对象 当我们实例化对象后,有的对象可能只使用一次,之后就没用了。这个时候我们往往要主动去析构它,否则会占着浪费空间。但是如果遇到大量的这种情况,我们并不想每次都去创建对象、调用、析构,这样会写出很多重…

软考 系统架构设计师系列知识点之大数据设计理论与实践(15)

接前一篇文章:软考 系统架构设计师系列知识点之大数据设计理论与实践(14) 所属章节: 第19章. 大数据架构设计理论与实践 第4节 Kappa架构 19.4.5 常见Kappa架构变型 1. Kappa架构 Kappa是Uber提出的流式数据处理架构&#xff0…

传统与创新的交响:『线上求签祈福』游戏案例赏析

Part1. 设计背景 在当代社会,寺庙文化正经历一场复兴,尤其受到年轻一代的热烈欢迎。无论是在传统的节假日还是平日里,寺庙总是吸引着众多年轻人前来,他们怀着虔诚的心祈求平安健康或财富好运。在面对生活中难以抉择或无法掌控的情…

JAVA-服务器搭建-创建web后端项目

首先打开IDEA 点击新建项目 写好名称-模板选择 Web应用程序 -语言选择 Java 构建系统选择 Maven 然后点击下一步 选择版本-选择依赖项 Web Profile 点击创建 点击当前文件-选择编辑配置 选择左上角的加号-选择Tomcat服务器-选择本地 点击配置-选择到Tomcat目录-点击确定 起个…

创建会计凭证:BAPI_ACC_DOCUMENT_POST 增强字段

创建会计凭证:BAPI_ACC_DOCUMENT_POST 增强字段 在ABAP程序中使用BAPI_ACC_DOCUMENT_POST的时候,如果有些字段在Tables参数中没有,比如,现在大家都用Reason code来作为现金流量表的表现方案。但是在BAPI_ACC_DOCUMENT_POST的acco…

Java新特性(jdk8)

第一章-lambda表达式 1.函数式编程思想和Lambda表达式定义格式 1.面向对象思想: 强调的是找对象,帮我们去做事儿 比如:去北京 -> 强调的是怎么去,火车,高铁,飞机,汽车,自行车,腿儿 2.jdk8开始有了一个新的思想:函数式编程思想: 强调的是结…

FreeRTOS之任务挂起和恢复

1.本文介绍FreeRTOS的任务挂起和恢复函数。任务删除后将不再存在,不能恢复,而任务挂起是暂停任务,可以通过调用函数进行恢复。FreeRTOS任务挂起和恢复的主要步骤如下: (1)将相关的宏定义设置为1&#xff1…

OPAM模型(细粒度图像分类)

OPAM模型(细粒度图像分类) 摘要Abstract1. OPAM1.1 文献摘要1.2 细粒度图像分类1.3 研究背景1.4 OPAM模型创新点1.5 OPAM模型1.5.1 补丁过滤1.5.2 显着性提取1.5.3 细粒度区域级注意模型对象-空间约束方法(Object spatial constraint&#xf…

钟薛高创始人称卖红薯也把债还上:网友,您可千万别……

网红雪糕品牌钟薛高,是真的网红属性强到让所有消费品牌羡慕。 纵使跌落神坛、纵使站在「破产」边缘,依然话题感满满,隔段时间,总能上一个热搜。 比如欠薪上热搜、产品降价上热搜、甚至官网微博微信停更,也得上个热搜&…

MLLM | InternLM-XComposer2-4KHD: 支持336 像素到 4K 高清的分辨率的大视觉语言模型

上海AI Lab,香港中文大学等 论文标题:InternLM-XComposer2-4KHD: A Pioneering Large Vision-Language Model Handling Resolutions from 336 Pixels to 4K HD 论文地址:https://arxiv.org/abs/2404.06512 Code and models are publicly available at https://gi…

.net core webapi 添加日志管理看板LogDashboard

.net core webapi 添加日志管理看板LogDashboard 添加权限管理&#xff1a; 我们用的是Nlog文件来配置 <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-project.org/schemas/NLog.xsd"xmlns:xsi"http:/…

网络基础-TCP/IP和OSI协议模型

一、OSI和TCP/IP模型 二、OSI七层模型 三、TCP/IP模型 参考&#xff1a;https://www.cnblogs.com/f-ck-need-u/p/7623252.html

Scanpy(1)数据结构和样本过滤

注&#xff1a;主要讲述scanpy处理数据的结构、数据过滤&#xff08;生信领域&#xff09;和数据预处理&#xff08;和机器学习类似&#xff0c;但是又有不同。&#xff09; 1. Scanpy简介与安装 Scanpy 是一个可扩展的工具包&#xff0c;用于分析与 AnnData&#xff08;一种…

螺纹滑牙的原因有哪些——SunTorque智能扭矩系统

螺纹滑牙的原因&#xff0c;通常是由于在旋紧或旋松过程中&#xff0c;螺纹副之间的摩擦力不足以维持所需的预紧力或工作载荷&#xff0c;导致螺纹副的相对位置发生变化。这种现象可能由多种因素引起&#xff0c;包括材料选择不当、设计不合理、制造工艺缺陷、环境因素以及使用…

欧科云链:香港虚拟资产OTC合规在即,技术监管成市场规范关键

4月12日香港OTC发牌制度公众咨询结束后&#xff0c;欧科云链研究院在星岛日报发表专栏文章&#xff0c;分享对香港OTC市场的调研情况&#xff0c;并提出“技术监管是香港OTC及Web3生态走向规范的关键”。欧科云链研究院认为&#xff0c;随着OTC监管及虚拟资产现货ETF等事件向前…

DC30V36V60V100V转9V、12V/1.5A方案 车灯驱动芯片IC H5028L ,高性价比,皮实耐抗

DC24V、30V、36V、60V、100V转9V、12V/1.5A方案&#xff0c;以及车灯驱动芯片IC&#xff0c;这通常涉及到电源转换和驱动电路的设计。这些方案的目标是将一个较高的直流电压&#xff08;如24V、30V、36V、60V或100V&#xff09;转换为较低但稳定的直流电压&#xff08;如9V或12…

Leetcode 第 394 场周赛

Leetcode 第 394 场周赛 1. [统计特殊字母的数量 I](https://leetcode.cn/problems/count-the-number-of-special-characters-i/)2. [统计特殊字母的数量 II](https://leetcode.cn/problems/count-the-number-of-special-characters-ii/)3. [使矩阵满足条件的最少操作次数](htt…

前端工程化02-复习jQuery当中的插件开发

2、jQuery插件开发 在我们开发的时候、有时候jQuery提供的方法并不能满足我们的需求&#xff0c;如果我们想给jQuery扩展一些其他的方法&#xff0c;那这种情况下&#xff0c;可能会需要写一个插件 jQurey官网&#xff1a;jquery.com 例如一些、图片懒加载插件、滚动的插件、…

BUUCTF-MISC-04大白

题目&#xff1a;让图片全面显示宽高 更改高宽一致 发现大白没有完全显示&#xff0c;优先考虑到图片高度隐写,猜测是FLAG隐藏在少掉的部分里&#xff0c;所以需要修改图片的高度与宽一致 我们借助010工具完成操作 根据内容可以看到高和宽不一样&#xff0c;这时候&#xff0…

图像处理基础知识

图像处理基础知识 图像 1、模拟图像 模拟图像&#xff0c;又称连续图像&#xff0c;是指在二维坐标系中连续变化的图像&#xff0c;即图像的像点是无限稠密的&#xff0c;同时具有灰度值&#xff08;即图像从暗到亮的变化值&#xff09;。 2、数字图像 数字图像&#xff0…