主页 > imtoken官方安卓版下载教程 > 58同城iOS客户端组件流量分析统计实践

58同城iOS客户端组件流量分析统计实践

出品 | CSDN(ID:CSDNnews)

随着需求场景的变化,客户端的架构也在不断演进。 支持并行研发已经成为大型客户端APP架构最基本的需求。 并行研发可以大大提高研发效率,但同时也带来了一些管理和维护问题。 本文主要介绍基于并行研发架构,如何方便快捷的分析ipa中某个组件占用的体积,并能对APP中的所有组件形成版本统计,快速比较两个版本组件的体积综艺之前和之后。

比特币符号对照表_808比特币创始人颜万卫 炮制比特币风险大_比特币主连比特币连续的区别

背景介绍

随着业务的发展,58同城已经实现了平行研发。 目前,58拥有租房、房客、招聘、二手车、黄页等多条业务线。 每个业务线在58 APP中都有一个或多个业务豆荚。 并行研发极大地提高了研发效率,但也引入了新的问题。 众所周知,APP量是APP的一个重要性能指标,APP量对APP下载量和留存量有着重要的影响。 因此,APP瘦身是一个经久不衰的趋势。 的话题。 为实现APP瘦身,需要明确各业务模块各自的代码和资源量。 基于这样的背景,58开始探索如何快速便捷地分析业务模块的体量和增量。

比特币主连比特币连续的区别_比特币符号对照表_808比特币创始人颜万卫 炮制比特币风险大

常用技术手段介绍

目前组件大小分析常用的技术方法有两种: 1. 空项目接入组件 将组件接入空项目,比较编译前后的包大小,增量为业务模块体积。 这种方案比较容易想到,但是58同城对代码拆分的粒度比较细,很难独立编译运行单个业务模块,需要多次编译才能得到各自的卷多个组件集,这是低效的。 因此,本方案不适用于58同城。 2、Linkmap文件分析 Linkmap文件分析是目前比较主流的技术手段。 它的原理是借助应用程序链接时生成的链接映射文件来分析组件体积。 linkmap文件格式如图1所示:

808比特币创始人颜万卫 炮制比特币风险大_比特币符号对照表_比特币主连比特币连续的区别

图1主要包括以下信息: 基于以上对linkmap文件的信息分析,根据文件号可以得到Mach-O文件中__TEXT段和__DATA段的数据来源和大小,从而确定每个组件的代码量。 得到linkmap文件后,就可以计算出每个section中的volume increment来自哪个target文件。 进一步地,根据目标文件的路径,可以知道目标文件属于哪个组件。 与第一种方案相比,该方案的效率得到了显着提升。 APP只需要编译一次,避免多次编译打包。 但是这种方案也有以下缺点: 58同城使用cocoapods管理的组件很多,这些组件的路径可能非常多,一个组件下可能有多个静态库。 58同城项目一共有63个组件,随着垂直业务的翻译和中间件的引入,APP组件也会不断变化。 由于linkmap文件对应的文件信息是目标文件的绝对路径,所以需要维护一个映射表来确定哪些路径文件属于哪个组件。 但是随着组件的变化,这个映射表可能会被频繁修改。 而且在不同的打包机上,组件的绝对路径是不一致的,所以在不同的服务器上打包也需要修改相应的映射表来分析组件的体积。 除了代码,组件还有更多的资源文件。 在58同城APP中,代码与资源的比例达到了12:5。 因此,对组件资源的统计也是很有必要的。 linkmap文件中只记录二进制链接信息,不包括资源信息,所以只能统计代码量,不能统计资源量。 如果要统计每个组件的资源,需要额外遍历组件路径下的所有资源。 除了以上两个问题,linkmap文件还有一个难以察觉的问题。 链接器在工作时会按照一定的顺序进行链接。 链接时,如果目标文件中段中的数据已经存在于可执行程序中,则不会再链接到可执行文件中。 这就带来了一个问题。 如果A组件和B组件各section有很多重复的内容,linkmap文件只记录最先参与链接的组件。 基于58现有的架构比特币符号对照表,每个业务组件依赖大量重复的中间件,所以相同的符号有很多重复,不同的业务组件之间不依赖,所以在编译链接的时候,基本上可以作为组件中的一个类,它们都是按顺序连续进行的,这就导致先参与编译链接的组件承担了其他组件公共部分的体积。

比特币符号对照表_比特币主连比特币连续的区别_808比特币创始人颜万卫 炮制比特币风险大

58个技术解决思路

58目前使用的是cocoapods管理组件,每个组件都是一个独立的pod。 为了加快编译速度,我们为每个组件创建了静态库pod和源码pod。 因此,我们期望利用静态库pod的编译信息直接分析出静态库的体积和各个pod中资源的体积,而不需要通过宿主工程链接获取信息。 获取链接静态库体积和资源体积后,保存每个pod每个版本的数据,提取任意两个版本的数据,形成对应的excel表格,让组件的体积变化一目了然. 由以上描述可知,整个方案的关键步骤是能否模拟链接器的工作过程。 因此,我们需要了解以下两点: 1.静态库的构成 在介绍静态库的构成之前,我们先简单介绍一下Mach-O文件。 Mach-O的全称是Mach Object,是一种特定的文件格式。 通常,比较常见的文件包括:应用程序、目标文件、动态库、bundle等。图2显示了可执行文件的二进制表示。

808比特币创始人颜万卫 炮制比特币风险大_比特币主连比特币连续的区别_比特币符号对照表

图2 Mach-O文件主要分为5个部分,即: 其中,Header是文件的头部信息,包括CPU信息、文件类型、Commands数量、Size信息。 LoadCommands 描述了文件的加载信息。 加载信息很多。 加载的段、符号表、动态库信息等都是在LoadCommands中获取的。 text部分记录了代码信息,比如类名字符串、方法名字符串、汇编指令等。 iOS中的数据段大部分存储类的结构信息和数据指向的文本段的地址,小部分字节存储静态变量。 字符串表记录了全局符号串,符号表记录了符号与地址的映射关系。 接下来介绍静态库的组成。 通过MachOView我们可以知道静态库和可执行文件中存在多架构文件。 (如图3所示)

808比特币创始人颜万卫 炮制比特币风险大_比特币主连比特币连续的区别_比特币符号对照表

图3中的每个架构由一个符号表Header、一个符号表、一个字符串表和多组目标文件Header+目标文件组成,每个目标文件都是一个单独的Mach-O文件。 从性能上看,一个静态库的大小可能高达几百兆,但最终链接后整个可执行文件的大小只有几十兆,这意味着其中的大量数据信息链接时静态库被删除。 弃。 为什么静态库链接前后差距这么大? 经过排查,发现静态库链接前较大而链接后较小的原因主要有以下几个原因:具有多种架构信息的Mach-O文件是fat二进制文件,而这些文件中的每一个信息每个架构都是独立的,多个架构意味着体积会呈指数级增长。 但是,用户下载的应用上传到App Store后,只存在一种架构,可执行文件中不存在其他架构的信息。 同理,APP在真机调试运行时,也是以单体架构的形式存在。 为了解决架构频繁升级带来的兼容性问题,苹果引入了bitcode。 Bitcode作为编译过程中产生的中间代码,可以转换成任何体系结构的机器码。 当有新模型或新架构产生时,中间代码可以快速生成新的二进制文件供用户下载。 因此,bitcode作为中间信息,不会出现在用户下载的可执行文件中。 开发者可以选择性的使用bitcode。 在58同城,bitcode是关闭的。 因此,提交给市场的可执行文件中是没有bitcode信息的。 因此,包含 bitcode 数据的静态库在链接之前会过大。

Mach-O 文件中存在一个 __DWARF 部分。 该段存放开发者的调试信息,如文件信息、变量信息等。__DWARF段主要用于调试,其数据格式为DWARF格式。 上传到App Store时,会连同符号表一起剥离。 在可执行文件中。 符号表是符号地址和符号之间的映射关系。 从安全的角度考虑,大部分APP在上传到App Store时都会将符号表中的本地符号去掉。 以上四个方面是静态库本身体积比真正链接后的体积大很多的原因。 以微博SDK为例,本地静态库大小为13.3MB。 拆分架构、剥离bitcode、剥离调试信息、剥离符号表后,其大小为793KB。 但是这个793KB并不是链接到可执行文件的实际大小。 在真实的arm64设备上,Weibo SDK的真实大小为202KB,与793KB相差很大。 造成这种差异的主要原因是链接器对文件的处理,所以有必要了解链接器在链接过程中做了哪些操作,才能准确分析静态库的体积。 2. 链接器的工作流程 链接器的作用是链接编译好的目标文件并输出可执行文件。 其工作流程主要包括:空间地址重分配、符号解析和重定位。 空间地址重分配是指将参与链接的目标文件的各个段的数据收集起来,放到一个统一的文件中。

符号解析和重定位是指对可执行文件的符号信息进行解析和调整,并对空间地址重分配后的地址信息进行更正,而不是对空间进行修改和调整。 因此,在链接过程中,对可执行文件大小影响较大的是空间地址重新分配的过程。 对于多个目标文件,链接器如何重新分配空间地址? 链接的空间分配策略主要有两种: 顺序堆叠是指将输入的目标文件依次堆叠,形成一个统一的文件。 这个方案很简单,但是空间浪费很严重。 因为每个目标文件中都存在相似的数据和结构。 similar segment merging是链接器实际使用的策略,即合并同一个段的相同数据,所以最终二进制文件中同一个段的数据量会大大减少。 例如目标文件ao和目标文件bo的(__TEXT, __objc_methname)中存在helloWorld的方法名,经过链接器链接后,最终的可执行文件中只有一个helloWorld。 以目标文件Hello.o和目标文件World.o为例,假设两个目标文件中都存在方法名“thisIsHello”和方法名“thisIsWorld”。 (如图四、图五所示)

808比特币创始人颜万卫 炮制比特币风险大_比特币主连比特币连续的区别_比特币符号对照表

图 4

比特币主连比特币连续的区别_808比特币创始人颜万卫 炮制比特币风险大_比特币符号对照表

图 5

最终链接后,可执行文件中只存在一个“thisIsHello”和一个“thisIsWorld”,如图 6 所示。

比特币主连比特币连续的区别_比特币符号对照表_808比特币创始人颜万卫 炮制比特币风险大

图 63. 解决方案流程 基于以上信息,58 的组件体积分析解决方案可以归纳如下: 通过 lipo -thin 命令提取指定架构的二进制文件。 提取arm64架构静态库的目的是减少工作量。 由于arm64和armv7文件的数据结构不同,比如Command结构segment_command和segment_command64,字节数不一致。

struct segment_command { /* for 32-bit architectures */
uint32_t cmd; /* LC_SEGMENT */
uint32_t cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32_t vmaddr; /* memory address of this segment */
uint32_t vmsize; /* memory size of this segment */
uint32_t fileoff; /* file offset of this segment */
uint32_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};。
struct segment_command_64 { /* for 64-bit architectures */
uint32_t cmd; /* LC_SEGMENT_64 */
uint32_t cmdsize; /* includes sizeof section_64 structs */
char segname[16]; /* segment name */
uint64_t vmaddr; /* memory address of this segment */
uint64_t vmsize; /* memory size of this segment */
uint64_t fileoff; /* file offset of this segment */
uint64_t filesize; /* amount to map from the file */
vm_prot_t maxprot; /* maximum VM protection */
vm_prot_t initprot; /* initial VM protection */
uint32_t nsects; /* number of sections in segment */
uint32_t flags; /* flags */
};

因此,不同架构的二进制文件需要根据不同的字节数进行解析,这在一定程度上增加了开发成本。 目前市面上的主流机型都是arm64架构,所以我们可以暂且统计一下64位架构下的体量。其主要流程如图7中的流程图所示

808比特币创始人颜万卫 炮制比特币风险大_比特币符号对照表_比特币主连比特币连续的区别

图 7 如何解析 Mach-O 格式的文件? 假设文件读入内存为NSData * fileData,解析Header信息的方式为:

//获取mach-o header
    mach_header_64 mhHeader;
    tmpRange = NSMakeRange(range.location, sizeof(mach_header_64));
    [fileData getBytes:&mhHeader range:tmpRange];

了解了Mach-O文件的格式后,就可以知道文件的某种数据结构在二进制文件的范围内,那么就可以在指定范围内按照二进制文件的指定结构读取数据. Mach-O文件中有多种数据类型,主要有:字符串(S_CSTRING_LITERALS)、4字节常量(S_4BYTE_LITERALS)、8字节常量(S_8BYTE_LITERALS)、16字节常量(S_16BYTE_LITERALS)等。解析Mach -O 文件按照上面的步骤。 得到section的section_64后,可以根据section_64的flags判断数据类型。

section_64  sectionHeader;
Type = sectionHeader.flags & SECTION_TYPE;

然后根据数据类型获取数据,以segment+section为字符串key保存到目标文件的字典中。

case S_CSTRING_LITERALS:{

                            NSArray *array = [self read_strings:secRange fixlen:sectionHeader.size fromFile:fileData];
                            [objcMachO.sections setObject:array forKey:sectionName];
                        }

扫描完所有目标文件后,合并每个目标文件的字典,保证每个key对应的数组中没有重复数据。 58同城将提取的数据输出到一个plist中,如图8所示。

比特币主连比特币连续的区别_比特币符号对照表_808比特币创始人颜万卫 炮制比特币风险大

图 8 使用 libxl 将任意两个版本的数据处理成一个 Excel 文件。

比特币符号对照表_比特币主连比特币连续的区别_808比特币创始人颜万卫 炮制比特币风险大

方案实施过程

基本方案确定后,如何实施是关键。 在启动程序之前,首先要考虑的是工具选择的问题。 许多工具可以创建为可视化 UI 应用程序或命令行工具。 具体形式取决于工具使用的场景。 考虑到未来可能将价体积分析和监控集成到可持续交付工具中,通过将工具创建为命令行工具来自动化和保持可扩展性可能会更好。 希望该工具可以输入任意文件路径,分析该路径下的资源和代码量,并输出plist数据文件。 输入任意两个版本的plist文件,形成对照表,以Excel文件的形式输出。 在实际开发过程中,主要存在的问题及解决方法如下:静态库按照智能、静态库符号表Header、静态库符号表、静态库字符串表、目标文件Header、目标文件的顺序存储数据。 当静态库中有多个目标文件时,目标文件Header和目标文件会依次倒序排列。 静态库中的目标文件排列不紧密,但存在8字节对齐问题。 当目标文件中的字节数小于8的倍数时,不足的字节会被存入data 0来补满字节。 但是静态库符号表不存在8字节对齐问题。 静态库符号表的大小为4+8*N字节。 按照8字节对齐,静态库字符串表会在静态库符号表末尾补4个字节。 事实上,两者是紧密结合的。 ,所以扫描文件时要注意字节对齐。

静态库作为一个整体是一个独立的文件,其地址是连续的。 无论静态库符号表Header、静态库符号表、静态库字符串表、目标文件头还是目标文件,它们的物理位置偏移都是相对于静态库的。 但是在object文件作为一个独立的Mach-O文件中,其文件中记录的文件偏移量是相对于object文件本身的offset。 例如目标文件ao的起始位置在静态库的0x1000处,目标文件ao中字符串表的偏移量为0x2000,那么在扫描ao中的字符串表时,应该从静态库的0x3000处开始静态库。 在合并模拟链接器的相似节时,需要提取和翻译每个节的信息,否则很难确定是否有重复的内容。 以字符串为例,字符串表存储的是连续的字符串信息。 在合并两个目标文件的字符串表时,需要明确每个字符串表中存储了哪些字符串,每个字符串的长度是多少。 否则很难简单的按字节比较数据。 在Mach-O文件中,英文字符串存放在__cstring中,每个字符占1个字节,以0x00结尾。 汉字每个占2个字节,以0x0000结尾。 中文字符串存储在 __ustring 中,而不是在字符串表或 __ctring 中。 获取中文十六进制数据后,需要获取编码格式为NSUTF16LittleEndianStringEncoding的中文。

得到中文字符串后,数据合并就比较容易了。 目标文件和下一个目标文件的文件头在字节对齐后相邻排列。 如果要获取下一个目标文件的头,必须指定当前目标文件的范围。 目标文件的Header信息中存储了一个size字段,可惜这个字段不等于目标文件的大小。 因此,58同城采取了间接的方式。 经过观察,发现目标文件的字符串表总是在末尾,也就是说,目标文件的字符串表字节对齐后,后面的地址就是下一个目标文件Header的地址. 上面是根据多个目标文件的情况来分析静态库的。 但是,在实际情况中,存在整个静态库中只有一个目标文件的情况。 此时静态库的数据存储顺序从smart->静态库符号表Header->静态库符号表->静态库字符串表->目标文件Header->目标文件的顺序简化为只有一个目标文件。 因此,需要针对这种特殊情况进行调整。 除了这种情况,静态库还有嵌套的情况,就是目标文件的相邻数据可能不是目标文件的Header,而是一个.a文件。 所以每个静态库都需要递归处理。 __TEXT 和__DATA 分别存储不同的数据。 代码的文本信息,包括:类名、方法名、字符串、汉字串、汇编指令等,都存在于__TEXT段中。

可以说__TEXT更接近于源代码信息,所以苹果给应用加了一层保护壳,App Store中的所有应用都对__TEXT进行了加密,只有在iOS系统运行应用时才会解密. 所谓砸壳,通常是指解密__TEXT。 Apple之所以不对__DATA进行加密,是因为__DATA主要存放__TEXT中的数据地址和类结构信息,data段不直接存放文本数据。 以__DATA中的__objc_selrefs段为例。 __objc_selrefs 存储代码中使用的方法名称。 在Mach-O文件中,__objc_selrefs将字符串地址存储在__TEXT段中的__objc_methname段中。 ,而不是直接存储字符串化的方法名称。 在可执行文件中,__objc_selrefs 存储链接器符号解析和重定位后的地址。 但是在静态库中,__objc_selrefs存储的是地址0。在主要存储类结构信息的__objc_const段中,存储的数据也是0。因此,在__DATA段上合并相似段是比较困难的,因为不可能知道每个地址结构中存储的是哪个类。 但是这样不会有太大的影响,因为虽然类结构中的数据为0,但是数量和占用空间都是正确的,如果有相同的类结构,是不能连成一个可执行程序的,所以可以认为静态库中__DATA段的大小接近链接后的大小。

上面主要讲解了如何扫描和处理静态库,那么如何处理资源呢? 组件的静态库pod在资源统计上有一个天然的优势,就是组件的xib和storyboard资源已经编译成nib文件,不需要再重新编译。 nib文件的大小就是ipa包中对应的xib或者storyboard文件的大小。 xcasset是Apple推出的用于存储图片资源的文件。 xcasset中存储的图片资源会被编译压缩,App Store会根据用户手机的屏幕来决定是下发2x图还是3x图。 为了保证统计的资源量接近在线用户的真实资源量,需要编译xcasset文件。 Xcode提供了atool命令,可以根据指定的模型对xcasset文件进行压缩编译。 在pod组件的路径下,有很多中间件的demo、文档、git信息,所以在遍历pod的路径时需要屏蔽这类文件和路径。 否则会对pod组件进行额外的数据统计甚至重复统计。 在58同城项目中,虽然有些pod组件是相互独立的,但无论是在业务上还是团队划分上,都属于一个模块。 因此,在获取到扫描数据后,需要将各个pod按模块进行整合展示。 以安居客为例,在58同城中,安居客模块占用了6个pod组件,所以需要统计这6个pod的整体数据,并在Excel中展示。

比特币符号对照表_比特币主连比特币连续的区别_808比特币创始人颜万卫 炮制比特币风险大

数据显示

目前该方案已成为58同城各版本组件量分析统计的重要手段。 并经过了3个版本的检测。 与发布时的数据对比,目前整体体积误差率控制在10%以内,体积增量误差率在5%以内。 通过组件分析和统计,58对整个项目的代码和资源体量结构有了更清晰的了解,可以快速帮助58评估业务接入和SDK接入的体量成本。 图9是58同城8.24版本和8.25版本的数据对比。

比特币符号对照表_比特币主连比特币连续的区别_808比特币创始人颜万卫 炮制比特币风险大

图 9

比特币主连比特币连续的区别_808比特币创始人颜万卫 炮制比特币风险大_比特币符号对照表

总结

该方案为多团队并行研发绩效指标的建立提供了依据,为APP瘦身提供了数据方向。 它的优点主要体现在以下几点: 参考资料:1.Mach-O的有趣探索:加载过程,2.《程序员的自我修养》3.OS X ABI Mach-O文件格式参考,4.libxl使用文档,5、linker和loader的基本工作原理比特币符号对照表,作者:邓竹丽,58同城用户价值增长部iOS技术部高级研发工程师。 专注于客户端架构和性能优化。 目前主要负责58iOS客户端微信中间件和APP工厂效率提升工具的研发。 【结尾】

比特币主连比特币连续的区别_比特币符号对照表_808比特币创始人颜万卫 炮制比特币风险大

热点文章推荐

比特币符号对照表_808比特币创始人颜万卫 炮制比特币风险大_比特币主连比特币连续的区别点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

808比特币创始人颜万卫 炮制比特币风险大_比特币符号对照表_比特币主连比特币连续的区别
你点的每个“在看”,我都认真当成了喜欢