程序地带

【Android渲染】在onDraw()中创建对象的隐形成本


熟悉Android自定义View的人大概都知道:


不要在onDraw里创建对象


大家在讲到这里,理由大概都是:


onDraw()被调用快速高频 --> 快速频繁申请内存 —> 频繁GC–> 线程挂起 --> UI卡顿


当然,上面的理由重要且正确,没有什么可说的。因为它明显地写在了onDraw()里,你一看就能联想到这些内容,所见即所得。


今天聊一个容易被忽略(或完全不知道)的隐形成本:


All that is bad enough, but it's getting worse.


我们重写onDraw()方法是为了自定义View,这时创建的对象很可能是与View绘制相关的Paint, Path, Typeface等;在onDraw()中调用Canvas API来绘制想要的图像,真实的绘制操作其实是调用了下层的C++代码(Skia/OpenGL ES),我们上面的提到了Paint等对象都是封装了C++层的native对象,那么问题来了。。。


“啥?要讲C++了?”


。。。逻辑很简单


C++之所以称之为native,是因为它不会自动地管理内存(没有垃圾回收器,手动管理内存),程序需要显示地调用析构函数来销毁对象以回收内存。这个时候只能借助Java的finalize()方法来finalizer(nativeObject), 而Java中的finalize()方法被设计为被垃圾收集前调用,这意味着前面大量创建的Java对象被回收时要先执行完finalize()方法中的代码,这导致了主线程进一步卡顿。


另外,析构函数的调用会锁native堆,这意味着什么?真正的绘制流程也会被高频阻塞,这个影响在Android 5.0之前体现在主线程,在Android5.0之后体现在RenderThread, 进一步加重了卡顿。


看到这里,可能有的朋友要问了:


你说的挺玄乎,可我知道这个有什么用呢? 我肯定不会在onDraw()里创建对象啊,也不会遇到你说的这个问题!


其实今天的内容是想引申一下,对于依赖的底层要有一些了解,它常常不会按照我们预期的方式来实现,之所以想写今天的内容,是因为联想到了自己在插件化实践中遇到的native缓存问题,解决起来也是煞费苦心。


reference

https://www.youtube.com/watch?v=HAK5acHQ53E&list=PLq_uWB0WqY0tVIrFZ41Wr5BZc9B_wf-XW&index=26


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/waterinsidewater/article/details/112761032

随机推荐

Java简单方法使用Day3

学习目标:第五节简单方法使用学习内容:使用简单方法packagedaythree;publicclasstestone{publicstaticvoiddemomethod...

biegaowoxiongdi 阅读(889)

pidstat_pidstat

pidstat概述pidstat是sysstat工具的一个命令,用于监控全部或指定进程的cpu、内存、线程、设备IO等系统资源的占用情况。pidstat首次运行时显示自系统启动开始的各项...

weixin_39670511 阅读(152)

jq动态新增删除指定表单数据

jq动态新增删除指定表单数据

实现效果:点击新增会新增一块表单数据,点击删除则隐藏对应表单数据,页面我用了layui框架渲染页面效果html代码<divid="pay...

向宇it 阅读(359)

pidstat_进程实时监控pidstat命令详解

pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存、设备IO、任务切换、线程等。pidstat首次运行时显示自系统启动开始的各项统计信息࿰...

夜半侃侃谈 阅读(955)

嵌入式linux nand启动+tftp内核设备树+nfs文件系统

嵌入式linux nand启动+tftp内核设备树+nfs文件系统

烧写自己的系统利用正点原子修改过的MFG_TOOL烧写自己的系统注意名字不要变这里主要是为了烧写uboot的。因为uboot不能直接通过uboot本身更新自己所以上面才用了mfg_tool来进行ubo...

我歌月徘徊、 阅读(444)

第十二章 二层基础协议-虚拟局域网VLAN

二层基础协议-虚拟局域网VLAN1、如何获悉一个园区网的拓扑连接CDP思科发现协议只有在思科设备上才能使用,会周期性发送CDP通告,给直连的邻居设备,邻居设备...

大提木 阅读(969)

pidstat_linux命令---pidstat

概述pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存、设备IO、任务切换、线程等。pidstat首次运行时显示自系统启动开始的各项统计信息...

weixin_39954889 阅读(997)