zoukankan      html  css  js  c++  java
  • iOS包大小计算

    一、LinkMap文件分析

          说明:LinkMap数据是根据文章《LinkMap文件分析》中方法实验实测数据。

    如何获得LinkMap文件
    1.在XCode中开启编译选项Write Link Map File 
    
    XCode -> Project -> Build Settings -> 把Write Link Map File选项设为yes,并指定好linkMap的存储位置
    2.工程编译完成后,在编译目录里找到Link Map文件(txt类型)
    在Build Settings里Path to Link Map File对应Link Map的路径,以下是默认路径: /Users/xxx/Library/Developer/Xcode/DerivedData/YourApp/Build/Intermediates.noindex/YourApp.build/Debug-iphoneos/YourApp.build/YourApp-LinkMap-normal-arm64.txt

    LinkMap里有了每个目标文件每个方法每个数据的占用大小数据,所以只要写个脚本,就可以统计出每个.o最后的大小,属于一个.a静态链接库的.o加起来,就是这个库在APP里占用的空间大小。

    LinkMap包含以下部分:

    # Path: .../*.app文件
    # Arch: arm64
    # Object files: .../*.o文件
    # Sections: Text和Data分类大小
    # Symbols: 与Object files对应起来,是Object files的详细Symbal信息,包括地址和大小
    # Dead Stripped Symbols:
    // linkmap.js
    var readline = require('readline'),
        fs = require('fs');
    
    var LinkMap = function(filePath) {
        this.files = []
        this.filePath = filePath
    }
    
    LinkMap.prototype = {
        start: function(cb) {
            var self = this
            var rl = readline.createInterface({
                input: fs.createReadStream(self.filePath),
                output: process.stdout,
                terminal: false
            });
            var currParser = "";
            rl.on('line', function(line) {
                if (line[0] == '#') {
                    if (line.indexOf('Object files') > -1) {
                        currParser = "_parseFiles";
                    } else if (line.indexOf('Sections') > -1) {
                        currParser = "_parseSection";
                    } else if (line.indexOf('Symbols') > -1) {
                        currParser = "_parseSymbols";
                    }
                    return;
                }
                if (self[currParser]) {
                    self[currParser](line)
                }
            });
    
            rl.on('close', function(line) {
                cb(self)
            });
        },
    
        _parseFiles: function(line) {
            var arr =line.split(']')
            if (arr.length > 1) {
                var idx = Number(arr[0].replace('[',''));
                var file = arr[1].split('/').pop().trim()
                this.files[idx] = {
                    name: file,
                    size: 0
                }
            }
        },
    
        _parseSection: function(line) {
        },
    
        _parseSymbols: function(line) {
            var arr = line.split('	')
            if (arr.length > 2) {
                var size = parseInt(arr[1], 16)
                var idx = Number(arr[2].split(']')[0].replace('[', ''))
                if (idx && this.files[idx]) {
                    this.files[idx].size += size;
                }
            }
        },
    
        _formatSize: function(size) {
            if (size > 1024 * 1024) return (size/(1024*1024)).toFixed(2) + "MB"
            if (size > 1024) return (size/1024).toFixed(2) + "KB"
            return size + "B"
        },
    
        statLibs: function(h) {
            var libs = {}
            var files = this.files;
            var self = this;
            for (var i in files) {
                var file = files[i]
                var libName
                if (file.name.indexOf('.o)') > -1) {
                    libName = file.name.split('(')[0]
                } else {
                    libName = file.name
                }
                if (!libs[libName]) {
                    libs[libName] = 0
                }
                libs[libName] += file.size
            }
            var i = 0, sortLibs = []
            for (var name in libs) {
                sortLibs[i++] = {
                    name: name,
                    size: libs[name]
                }
            }
            sortLibs.sort(function(a,b) {
                return a.size > b.size ? -1: 1
            })
            if (h) {
                sortLibs.map(function(o) {
                    o.size = self._formatSize(o.size)
                })
            }
            return sortLibs
        },
    
        statFiles: function(h) {
            var self = this
            self.files.sort(function(a,b) {
                return a.size > b.size ? -1: 1
            })
            if (h) {
                self.files.map(function(o) {
                    o.size = self._formatSize(o.size)
                })
            }
            return this.files
        }
    }
    
    if (!process.argv[2]) {
        console.log('usage: node linkmap.js filepath -hl')
        console.log('-h: format size')
        console.log('-l: stat libs')
        return
    }
    var isStatLib, isFomatSize
    var opts = process.argv[3];
    if (opts && opts[0] == '-') {
        if (opts.indexOf('h') > -1) isFomatSize = true
        if (opts.indexOf('l') > -1) isStatLib = true
    }
    
    var linkmap = new LinkMap(process.argv[2])
    linkmap.start(function(){
        var ret = isStatLib ? linkmap.statLibs(isFomatSize) 
                            : linkmap.statFiles(isFomatSize)
        for (var i in ret) {
            console.log(ret[i].name + '	' + ret[i].size)
        }
    })

    执行:

    node linkmap.js LinkMap-normal-arm64.txt -hl

    得到:

    YourSDK(YourSDK-arm64-master.o)    122.76KB

    二、xcodebuild总包大小分析

    分析:Release 包(arm64)为什么比debug包(x86_64)大那么多?

    分析步骤

    1.  抽出YourSDK的arm64看包大小(1.6M)

    lipo  -thin arm64 -output YourSDK_arm64.a YourSDK.framework/YourSDKls -al YourSDK_arm64.a
    -rw-r--r--  1 yushu.lxy  staff  1606208 11 18 15:58 YourSDK_arm64.a

    2.  整体

    size YourSDK_armv64.a
    __TEXT    __DATA    __OBJC    others    dec    hex
    86591    39492    0    1190617    1316700    14175c    YourSDK_arm64.a(YourSDK-arm64-master.o)
    30    240    0    4566    4836    12e4    YourSDK_arm64.a(libPods-YourSDK.a-arm64-master.o)

    查看.a文件下.o文件大小

    ar -t -v YourSDK_arm64.a
    rw-r--r--     501/20         5776 Nov 18 15:58 2019 __.SYMDEF SORTED
    rw-r--r--       0/0       1593168 Jan  1 08:00 1970 YourSDK-arm64-master.o
    rw-r--r--       0/0          6976 Jan  1 08:00 1970 libPods-YourSDK.a-arm64-master.o

    3.  详细

    size -m YourSDK_arm64.a
    YourSDK_arm64.a(YourSDK-arm64-master.o):
    Segment : 1316713
        Section (__TEXT, __text): 68676(比debug的包小)
        Section (__TEXT, __objc_methname): 8393
        Section (__TEXT, __cstring): 5091
        Section (__TEXT, __objc_classname): 1636
        Section (__TEXT, __objc_methtype): 1937
    Section (__TEXT, __literal16): 128(只有debug包有)
        Section (__TEXT, __literal4): 8(只有debug包有)
        Section (__TEXT, __literal8): 144(比debug的包小)
    Section (__TEXT, __eh_frame): 16480
        Section (__TEXT, __gcc_except_tab): 608
        Section (__TEXT, __ustring): 42
        Section (__TEXT, __const): 64
        Section (__DATA, __const): 1560
        Section (__DATA, __cfstring): 4736
        Section (__DATA, __objc_classlist): 400
        Section (__DATA, __objc_catlist): 8
        Section (__DATA, __objc_protolist): 56
        Section (__DATA, __objc_imageinfo): 8
        Section (__DATA, __objc_const): 24224
        Section (__DATA, __objc_selrefs): 2752
        Section (__DATA, __objc_protorefs): 8
        Section (__DATA, __objc_classrefs): 592
        Section (__DATA, __objc_superrefs): 192
        Section (__DATA, __objc_ivar): 252(比debug的包小)
        Section (__DATA, __objc_data): 4000
        Section (__DATA, __data): 672
        Section (__DATA, __bss): 32
        Section (__LD, __compact_unwind): 11424
        Section (__LLVM, __bundle): 1179193(+)
        total 1316700
    total 1316713
    YourSDK_arm64.a(libPods-YourSDK.a-arm64-master.o):
    Segment : 4838
        Section (__TEXT, __text): 0
        Section (__TEXT, __objc_classname): 30
        Section (__DATA, __objc_classlist): 8
        Section (__DATA, __objc_imageinfo): 8
        Section (__DATA, __objc_const): 144
        Section (__DATA, __objc_data): 80
        Section (__LLVM, __bitcode): 4480 (+)
        Section (__LLVM, __cmdline): 86 (+)
        total 4836
    total 4838

    YourSDK SDK实际大小应该是:1316713-1179193 = 137KB(与LinkMap分析接近)

    分析:

    上面段数据LLVM bundle部分是release包比debug包大的原因,是因为release包包含了bitCode数据

    参考《关于bitcode, 知道这些就够了

    (1)bitcode是源码和机器码之间的中间形式。

    (2)为什么苹果要强推bitcode?开发者把bitcode提交到App Store Connect之后,如果苹果发布了使用新芯片的iPhone,支持更高效的指令,开发者不需要做任何操作,App Store Connect自己就可以编译出针对新产品优化过的app并通过App Store分发给用户,不需要开发者自己重新打包上架。

    (3)苹果可以将bitcode代码进行一些逻辑等价的转换,使得代码的执行效率更高,体积更小。

    实验:APP的project开启bitcode和关闭bitcode,查看手机中app的实际大小,开启bitcode的包更小。

    size -m YourSDK_arm64.a
    YourSDK_arm64.a(YourSDK-arm64-master.o):
    Segment : 943490
        Section (__TEXT, __text): 53184
        Section (__TEXT, __objc_classname): 633
        Section (__TEXT, __objc_methname): 7919
        Section (__TEXT, __objc_methtype): 850
        Section (__TEXT, __cstring): 7352
        Section (__TEXT, __literal8): 64
        Section (__TEXT, __gcc_except_tab): 1724
        Section (__TEXT, __const): 112
        Section (__DATA, __const): 1864
        Section (__DATA, __cfstring): 4000
        Section (__DATA, __objc_classlist): 200
        Section (__DATA, __objc_protolist): 8
        Section (__DATA, __objc_imageinfo): 8
        Section (__DATA, __objc_const): 21760
        Section (__DATA, __objc_selrefs): 1776
        Section (__DATA, __objc_classrefs): 352
        Section (__DATA, __objc_superrefs): 24
        Section (__DATA, __objc_ivar): 620
        Section (__DATA, __objc_data): 2000
        Section (__DATA, __data): 96
        Section (__DATA, __bss): 40
        Section (__DATA, __common): 8
        Section (__LD, __compact_unwind): 15968
        Section (__LLVM, __bundle): 822914
        total 943476
    total 943490

    分析结论

    (1) LinkMap分析的大小不包含打入framework中的bundle信息,建议用LinkMap分析的包大小至少要加上bundle的大小。

    (2)经多次安装实验,真实安装包后, APP大小增长是比LinkMap给出的包大小大的。

    (3)给外部的包大小信息,暂时跟大家保持一致“使用LinkMap给出的数据”。

  • 相关阅读:
    ArcGis Desktop arcmap安装步骤
    ArcMap 中添加 ArcGis server
    arcgis server 安装
    哨兵数据处理,哨兵数据水体数据提取
    Web安全之SQL注入攻击技巧与防范(转)
    干货分享丨Python从入门到编写POC之初识OOP和类
    干货分享丨Python从入门到编写POC之爬虫专题
    干货分享丨XSS利用进阶
    CVE-2020-9484 Apache Tomcat反序列化漏洞浅析
    干货分享丨Python从入门到编写POC之常用的标准库
  • 原文地址:https://www.cnblogs.com/Xylophone/p/14156729.html
Copyright © 2011-2022 走看看