bugly怎么读_【腾讯Bugly干货分享】微信读书 iOS 性能优化-程序员宅基地

技术标签: bugly怎么读  

“8小时内拼工作,8小时外拼成长”这是大家共同的理想。除了每天忙于工作外,我们都希望能更多地区吸收领域内的新知识与新技能,从而走向人生巅峰。

Dev Club 是一个交流移动开发技术,结交朋友,扩展人脉的社群,成员都是经过审核的移动开发工程师。每周都会举行嘉宾分享,话题讨论等活动。

上一期我们邀请了腾讯SNG工程师“王少鸣”分享了《React Native项目实战总结》。

本期,我们邀请了腾讯WXG iOS开发工程师“姚海波”为大家分享《微信读书iOS性能优化》。

分享内容简介

微信读书作为一款阅读类的新产品,目前还处于快速迭代,不断尝试的过程中,性能问题也在业务的不断累积中逐渐体现出来。最近的1.3.0版本发布后,关于性能问题的用户反馈逐渐增多,为此,团队开始做一些针对性的性能问题优化。本次分享主要介绍我们发现问题、解决问题和预防问题的历程。

内容的大体框架:

如何发现性能问题

性能问题的解决方法

如何预防性能问题

优化成果

总结

分享人介绍:

姚海波 广州研发部 iOS开发工程师。负责过的产品:QQ邮箱iOS客户端,目前主要负责微信读书iOS客户端的开发。

下面是本期分享内容整理。

大家晚上好,我是来自广研的姚海波,大家可以叫我hypo。目前是微信读书项目中的iOS开发,主要负责阅读器相关的模块,还有APP整体性能优化方面的工作。

今天分享的内容是关于微信读书iOS开发过程中,我们解决性能问题的基本思路和方法,包括发现问题、解决问题和预防问题三个方面。

一、发现问题

首先,根据个人的开发经验,我不得不承认,当应用发展到一定程度后,性能问题就不可能完全避免。以往我们总是希望能寻找一种解决性能问题的一劳永逸的方法,其实是不太现实的。所以我们换个思路,如何尽早的发现性能问题,然后解决问题。

在发现问题方面,我们项目也并没有什么高招,主要有两个方面

用户反馈(包括测试人员) 受限于测试时间和用户反馈的积极性,性能问题往往到了比较严重的程度,开发人员才真正发现问题。

在线监控 主要有业务性能监控和卡顿监控

业务性能监控,主要在我们认为非常关键的操作路径,例如:

卡顿监控,是用了Bugly的工具,然后通过动态下发开关,用抽样的方法进行上报

还有一些反馈卡顿的用户,我们也会通过这个方法来查找问题

二、解决问题

然后,在解决性能问题方法,相信大家都累积了很多经验。

产生性能问题的原因多种多样,所以解决的办法也不尽相同,各种奇技淫巧都有可能派上用场,这里我大概介绍一下我们项目中用到的一些方面:

优化业务流程

合理的线程分配

预处理和延时加载

缓存

使用正确的API

1. 优化业务流程

性能优化看似高深,真正落到实处才会发现,最大的坑往往都隐藏在于业务不断累积和频繁变更之处。优化业务流程就是在满足需求的同时,提出更加高效优雅的解决方案,从根本上解决问题。从实践来看,这种方法解决问题是最彻底的,但通常也是难度最大的。

这是我们其中一个业务优化的案例

看似挺简单的优化,但真正落到实处,才会出现其中的坑有多大,所以重构优化的时候,还得有颗坚强的心!

2. 合理的线程分配

由于GCD实在太方便了,如果不加控制,大部分需要抛到子线程操作都会被直接加到global队列,这样会导致两个问题:

开的子线程越来越多,线程的开销逐渐明显,因为开启线程需要占用一定的内存空间(默认的情况下,主线程占1M,子线程占用512KB)。

多线程情况下,网络回调的时序问题,导致数据处理错乱,而且不容易发现。为此,我们项目定了一些基本原则:

UI操作和DataSource的操作一定在主线程。

DB操作、日志记录、网络回调都在各自的固定线程。

不同业务,可以通过创建队列保证数据一致性。例如,想法列表的数据加载、书籍章节下载、书架加载等。

合理的线程分配,最终目的就是保证主线程尽量少的处理非UI操作,同时控制整个App的子线程数量在合理的范围内。

3. 预处理和延时加载

预处理,是将初次显示需要耗费大量线程时间的操作,提前放到后台线程进行计算,再将结果数据拿来显示。

延时加载,是指首先加载当前必须的可视内容,在稍后一段时间内或特定事件时,再触发其他内容的加载。这种方式可以很有效的提升界面绘制速度,使体验更加流畅。(UITableView就是最典型的例子)

这两种方法都是在资源比较紧张的情况下,优先处理马上要用到的数据,同时尽可能提前加载即将要用到的数据。在微信读书中阅读的排版是优先级最高的,所在在阅读过程中会预处理下一页、下一章的排版,同时可能会延时加载阅读相关的其它数据(如想法、划线、书签等)。

4. 缓存

cache可能是所有性能优化中最常用的手段,但也是我们极不推荐的手段。cache建立的成本低,见效快,但是带来维护的成本却很高。如果一定要用,也请谨慎使用,并注意以下几点:

并发访问cache时,数据一致性问题。

cache线程安全问题,防止一边修改一边遍历的crash。

cache查找时性能问题。

cache的释放与重建,避免占用空间无限扩大,同时释放的粒度也要依实际需求而定。

5. 使用正确的 API

选择合适的容器;

了解imageNamed与imageWithContentsOfFile的差异(_imageNamed_适用于会重复加载的小图片,因为系统会自动缓存加载的图片;_imageWithContentsOfFile_仅加载图片)

缓存NSDateFormatter的结果。

寻找__(NSDate *)dateFromString:(NSString )string__的替换品

不要随意使用NSLog();

这方面主要还是靠经验的累积。上面只是列举了几种常规手段,相信大家在实践过程中,肯定还有很多的高招。

三、预防问题

经过一段时间的性能优化工作,我们团队达成了一项共识,与其花那么时间去发现问题,查问题,还不如多开发一些工具,让问题尽量暴露在开发阶段,最好达到避免共性问题。所以,我们总是想开发一些有意思小工具来做这种事情。

下面列举几个我们认识还挺有帮忙的工具:

1.内存泄露检测工具。

2.FPS/SQL性能监测工具条

3.UI/DataSource主线程检测工具

4.排版引擎自动化检测工具

5.书源检测工具

1. 内存泄漏检测工具

MLeakFinder,这个已经开源了,是我们团队中zeposhe的杰作。

在此之前,内存泄露引起的性能问题是很难被察觉的,只有泄露到了相当严重的程度,然后通过Instrument工具,不断尝试才得以定位。MLeakFinder能在开发阶段,把内存泄露问题暴露无遗,减少了很多潜在的性能问题。

2. FPS/SQL性能监测工具条

工具条是在DEBUG模式下,以浮窗的形式,实时展示当前可能存在问题的FPS次数和执行时间较长的SQL语句个数,是团队成员tower开发的。

FPS监测的原理并不复杂,虽然不是百分百准确,但非常实用,因为可以随时查看FPS低于某个阈值时的堆栈信息,再结合当时的使用场景,开发人员使用起来非常便利,可以很快定位到引起卡顿的场景和原因。SQL语句的监测也非常实用,对于微信读书,DB的读写速度是影响性能的瓶颈之一。因此在DEBUG阶段,我们监测了每一条SQL语句的执行速度,一旦执行时间超出某个阈值,就会表现在工具条的数字上,点击后可以进一步查询到具体的SQL操作以及实际耗时。

顶部工具条点击后,就可以查到具体是哪条sql语句慢

这个工具帮助我们在开发阶段发现了很多卡顿问题,尤其是一些不合理的SQL语句,例如:

在想法圏的优化过程中,利用这个工具,我们就发现想法圈第一次加载更多,执行的SQL语句耗时竟然达到了1000多毫秒。

_SELECT * FROM WRReview INNER JOIN WRUser ON WRReview.fromId = WRUser.vid WHERE WRReview.type & ? AND WRReview.createTime <= ? ORDER BY WRReview.createTime DESC , WRReview.itemId ASC LIMIT ?_

通过explain,可以发现这条SQL效率之低:

SEARCH TABLE WRReview

SEARCH TABLE WRUser USING INTEGER PRIMARY KEY (rowid=?)

USE TEMP B-TREE FOR ORDER BY

没有建立合适的索引,导致WRReview全表扫描。

排序字段没有索引,导致SQLite需要再一次B-TREE排序。

两字段排序,性能更低。

优化:给WRReview的 fromId _createTime_ 两个字段增加了索引,并去掉一个排序字段

_SELECT * FROM WRReview INNER JOIN WRUser ON WRReview.fromId = WRUser.vid WHERE WRReview.type & ? ORDER BY WRReview.createTime DESC LIMIT ?_

Explain的结果:

SCAN TABLE WRReview USING INDEX WRReview_createTime

SEARCH TABLE WRUser USING INTEGER PRIMARY KEY (rowid=?)

SQL执行时间直接降了一个数量级,到100毫秒左右。

3. UI/DataSource 主线程检测工具

该工具是为了保证所有的UI的操作和DataSource操作一定是在主线程进行。实现原理是通过hook UIView的setNeedsLayout,setNeedsDisplay,setNeedsDisplayInRect三个方法,确保它们都是在主线程执行。子线程操作UI可能会引起什么问题,苹果说得并不清楚,实际开发中我们遇到几种神奇的问题似乎都是跟这个有关。

app突然丢动画,似乎iOS系统也有这个bug。虽然没有确切的证据,但使用这个工具,改完所有的问题后,bug也好了(不止一次是这样)。

UI操作偶尔响应特别慢,从代码看没有任何耗时操作,只是简单的push某个controller。

莫名的crash,这当然是因为UI操作非线程安全引起的。

更多时候,子线程操作UI也并不一定会发生什么问题,也正因为不知道会发生什么,所以更需要我们警惕,这个工具替我们扫除了这些隐患。虽然,苹果表示,现在部分的UI操作也已经是线程安全了,但毕竟大部分还不是。DataSource的监测是因为我们业务定下的原则,保证列表DataSource的线程安全。

4. 排版引擎自动化检测工具

排版引擎是微信读书最核心的功能,排版引擎检测工具原本是为了检验排版引擎改进过程中准确性,防止因为业务变更,而影响原来的排版特性。实现原理是结合自动化脚本和App本身的排版引擎,给书库中的每一本书建立一个镜像,镜像的内容包括书籍的每一章每一页的截图。然后分析同一页码的两个不同版本的图片差异,就可以知道不同版本的排版引擎渲染效果。但是我发现,只要稍加改进,排版后记录每个章节排版耗时,就可以知道每个版本变化后同一个章节的耗时变化,以此作为排版引擎的性能指标。这个工具保证了微信读书,即使在快速迭代过程中也不会丢失阅读的核心体验。虽然这个工具无法在其它项目中复用,但是提醒了我们,可以通过自动化工具来保证产品最核心功能的体验。

这个虽然业务相关性比较强,但是对于某些应用的自动化测试也是有效的

5. 书源检测工具

微信读书为了支持正版版权,目前书源完全依赖于后台,不允许本地导入。书源的优劣的直接影响排版的效果和性能。为了解决了部分书籍无法打开或者乱码的问题,我们借助了后台同学的书源检测工具。对线上所有epub书籍(大概13,000本)进行扫描,按照章节大小进行排序。对于章节内容特别大的书籍重点检测,重新排版,解决了一批epub书籍无法打开的问题。同时针对章节内容乱码的问题,对所有txt的书籍进行了一次全量扫描,发现了一些问题,但还无法准确找出所有乱码的章节,这一点还在努力改善中。

四、优化成果

整体使用感受上,已经可以明显区分两个版本的性能差异,这一点也可以通过每天的用户反馈数据中得到验证。1.3.0和1.3.1分别发布一周后反馈的卡顿数从10个降到了3个,从总体反馈比例的2.8%降到0.8%。

某些关键业务,耗时也有明显改善。

极端案例的修复。超大的epub书籍已通过后台进行拆分,解决了无法打开书籍的情况。

针对低端机型,去掉了某些动画,交互更加流畅。

五、总结

通过上述介绍,我们可以看出,性能问题普遍存在,无可避免,与其花费大量时间,查找线上版本的性能问题,不如提高整体团队成员性能优化意识,借助性能查找工具,将性能问题尽早暴露在开发阶段,达到预防为主的效果。

问答环节

Q1:想问下你们 DB 操作这部分涉及到多线程读写是怎么处理的?

我们用了FMDB,它已经处理了这种情况。

Q2:主线程检测工具有开源吗?

这个暂时没有开源,但是会推动开源。

Q3:除了 sqlite 语句的优化之外,db 这部分还有没有其他方面的优化工作?

我们有一个自己的DB框架,是ORM的,做了很多优化的工作,最近刚开源,大家可以看看。

Q4:请问你们选择用sqlite的考量是什么, 有没有考虑过使用其他的db如realm?

选择sqlite是历史原因,因为我们已经基于sqlite做了一个高性能的DB框架,而且也是经过QQMail App验证的。realm有考虑过,但是因为不是开源,所以估计不用采用。

Q5:FMDB 的解决方案,我理解是放到一个队列里,虽然可以解决多线程读写的问题,但是队列的处理还是会阻塞住来自不同线程的请求,对么?

是的。我们一直也是读写都在同一条队列,其实并没有太明显的性能瓶颈, 因为在sqlite之上我们还有一层基于model的cache。

Q6:合理的使用线程,多线程之间的同步这块儿有什么方案或建议?

这里我们也并没有什么通用的方案,原则是尽量避免使用多线程。一定要用的时候,也是根据业务谨慎选择。

或者我们私下可以再具体讨论一些业务场景。

Q7:业务场景里会不会涉及到有读操作依赖写操作完成的情况,否则会出现读操作的数据不准确的情况。FMDB 感觉不能很好的解决这个问题。

读操作 依赖写操作完成,这种场景一定会有的。但是这种问题应该是业务流程自己控制,而不是DB应该考虑的事情,DB性一能保证的就是按照业务提交的顺序,顺序执行。

Q8:能不能问下 微信读书的数据库的记录 一般是在什么级别,百、千?有没有尝试去做过一些压测,数据量达到多少的时候会遇到瓶颈?

微信读书的数据库记录并不是很大,单表记录最多可能也就10w的数据级别。QQ邮箱的mailApp跟我们是用的同一套,但是数量级别远大于微信读书。目前发现的瓶颈是DB文件达到200M以上时,sqlite的性能会明显受到影响,不过具体原因还在调查中。有做过一些压力测试,用来对比CoreData,但是具体数据我这里暂时没有。

Q9:卡顿监控这块能详细说说么,用的是Bugly的哪个工具呢,抽样上报具体是怎么样的?

Bugly库里有这个接口可以用+ (void)enableBlockMonitor:(BOOL)enable

另外再动态下发一个开关,设置这个值就好了。

Q10:微信读书这么成功,方便说下她的架构吗?我觉得架构好才是她可优化的第一步。

哈哈,现在还远谈不上成功啦。架构要用图来画才方便看,我暂时还没总结整个app的架构, 可以看看关于阅读器epub渲染的一个架构。

Q11:sql对于版本升级时表结构发生变化时如何处理?特别是跨版本升级!

https://github.com/Zepo/GYDat... 这个是基本ORM的一个框架,会自动把model和sqlite表的字段做一个映射,升级的时候,如果发现sqlite缺少的字段,会自动创建。但是,因为sqlite不能修改字段,所以我们也只能用于新增字段。

Q12:你们的 db 是只有一个文件,还是尝试分文件存储的?

看业务需求,目前是多个DB文件。

更多精彩内容欢迎关注bugly的微信公众账号:

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

智能推荐

FTP命令字和返回码_ftp 登录返回230-程序员宅基地

文章浏览阅读3.5k次,点赞2次,收藏13次。为了从FTP服务器下载文件,需要要实现一个简单的FTP客户端。FTP(文件传输协议) 是 TCP/IP 协议组中的应用层协议。FTP协议使用字符串格式命令字,每条命令都是一行字符串,以“\r\n”结尾。客户端发送格式是:命令+空格+参数+"\r\n"的格式服务器返回格式是以:状态码+空格+提示字符串+"\r\n"的格式,代码只要解析状态码就可以了。读写文件需要登陆服务器,特殊用..._ftp 登录返回230

centos7安装rabbitmq3.6.5_centos7 安装rabbitmq3.6.5-程序员宅基地

文章浏览阅读648次。前提:systemctl stop firewalld 关闭防火墙关闭selinux查看getenforce临时关闭setenforce 0永久关闭sed-i'/SELINUX/s/enforcing/disabled/'/etc/selinux/configselinux的三种模式enforcing:强制模式,SELinux 运作中,且已经正确的开始限制..._centos7 安装rabbitmq3.6.5

idea导入android工程,idea怎样导入Android studio 项目?-程序员宅基地

文章浏览阅读5.8k次。满意答案s55f2avsx2017.09.05采纳率:46%等级:12已帮助:5646人新版Android Studio/IntelliJ IDEA可以直接导入eclipse项目,不再推荐使用eclipse导出gradle的方式2启动Android Studio/IntelliJ IDEA,选择 import project3选择eclipse 项目4选择 create project f..._android studio 项目导入idea 看不懂安卓项目

浅谈AI大模型技术:概念、发展和应用_ai大模型应用开发-程序员宅基地

文章浏览阅读860次,点赞2次,收藏6次。AI大模型技术已经在自然语言处理、计算机视觉、多模态交互等领域取得了显著的进展和成果,同时也引发了一系列新的挑战和问题,如数据质量、计算效率、知识可解释性、安全可靠性等。城市运维涉及到多个方面,如交通管理、环境监测、公共安全、社会治理等,它们需要处理和分析大量的多模态数据,如图像、视频、语音、文本等,并根据不同的场景和需求,提供合适的决策和响应。知识搜索有多种形式,如语义搜索、对话搜索、图像搜索、视频搜索等,它们可以根据用户的输入和意图,从海量的数据源中检索出最相关的信息,并以友好的方式呈现给用户。_ai大模型应用开发

非常详细的阻抗测试基础知识_阻抗实部和虚部-程序员宅基地

文章浏览阅读8.2k次,点赞12次,收藏121次。为什么要测量阻抗呢?阻抗能代表什么?阻抗测量的注意事项... ...很多人可能会带着一系列的问题来阅读本文。不管是数字电路工程师还是射频工程师,都在关注各类器件的阻抗,本文非常值得一读。全文13000多字,认真读完大概需要2小时。一、阻抗测试基本概念阻抗定义:阻抗是元器件或电路对周期的交流信号的总的反作用。AC 交流测试信号 (幅度和频率)。包括实部和虚部。​图1 阻抗的定义阻抗是评测电路、元件以及制作元件材料的重要参数。那么什么是阻抗呢?让我们先来看一下阻抗的定义。首先阻抗是一个矢量。通常,阻抗是_阻抗实部和虚部

小学生python游戏编程arcade----基本知识1_arcade语言 like-程序员宅基地

文章浏览阅读955次。前面章节分享试用了pyzero,pygame但随着想增加更丰富的游戏内容,好多还要进行自己编写类,从今天开始解绍一个新的python游戏库arcade模块。通过此次的《连连看》游戏实现,让我对swing的相关知识有了进一步的了解,对java这门语言也有了比以前更深刻的认识。java的一些基本语法,比如数据类型、运算符、程序流程控制和数组等,理解更加透彻。java最核心的核心就是面向对象思想,对于这一个概念,终于悟到了一些。_arcade语言 like

随便推点

【增强版短视频去水印源码】去水印微信小程序+去水印软件源码_去水印机要增强版-程序员宅基地

文章浏览阅读1.1k次。源码简介与安装说明:2021增强版短视频去水印源码 去水印微信小程序源码网站 去水印软件源码安装环境(需要材料):备案域名–服务器安装宝塔-安装 Nginx 或者 Apachephp5.6 以上-安装 sg11 插件小程序已自带解析接口,支持全网主流短视频平台,搭建好了就能用注:接口是公益的,那么多人用解析慢是肯定的,前段和后端源码已经打包,上传服务器之后在配置文件修改数据库密码。然后输入自己的域名,进入后台,创建小程序,输入自己的小程序配置即可安装说明:上传源码,修改data/_去水印机要增强版

verilog进阶语法-触发器原语_fdre #(.init(1'b0) // initial value of register (1-程序员宅基地

文章浏览阅读557次。1. 触发器是FPGA存储数据的基本单元2. 触发器作为时序逻辑的基本元件,官方提供了丰富的配置方式,以适应各种可能的应用场景。_fdre #(.init(1'b0) // initial value of register (1'b0 or 1'b1) ) fdce_osc (

嵌入式面试/笔试C相关总结_嵌入式面试笔试c语言知识点-程序员宅基地

文章浏览阅读560次。本该是不同编译器结果不同,但是尝试了g++ msvc都是先计算c,再计算b,最后得到a+b+c是经过赋值以后的b和c参与计算而不是6。由上表可知,将q复制到p数组可以表示为:*p++=*q++,*优先级高,先取到对应q数组的值,然后两个++都是在后面,该行运算完后执行++。在电脑端编译完后会分为text data bss三种,其中text为可执行程序,data为初始化过的ro+rw变量,bss为未初始化或初始化为0变量。_嵌入式面试笔试c语言知识点

57 Things I've Learned Founding 3 Tech Companies_mature-程序员宅基地

文章浏览阅读2.3k次。57 Things I've Learned Founding 3 Tech CompaniesJason Goldberg, Betashop | Oct. 29, 2010, 1:29 PMI’ve been founding andhelping run techn_mature

一个脚本搞定文件合并去重,大数据处理,可以合并几个G以上的文件_python 超大文本合并-程序员宅基地

文章浏览阅读1.9k次。问题:先讲下需求,有若干个文本文件(txt或者csv文件等),每行代表一条数据,现在希望能合并成 1 个文本文件,且需要去除重复行。分析:一向奉行简单原则,如无必要,绝不复杂。如果数据量不大,那么如下两条命令就可以搞定合并:cat a.txt >> new.txtcat b.txt >> new.txt……去重:cat new...._python 超大文本合并

支付宝小程序iOS端过渡页DFLoadingPageRootController分析_类似支付宝页面过度加载页-程序员宅基地

文章浏览阅读489次。这个过渡页是第一次打开小程序展示的,点击某个小程序前把手机的开发者->network link conditioner->enable & very bad network 就会在停在此页。比如《支付宝运动》这个小程序先看这个类的.h可以看到它继承于DTViewController点击左上角返回的方法- (void)back;#import "DTViewController.h"#import "APBaseLoadingV..._类似支付宝页面过度加载页

推荐文章

热门文章

相关标签