iOS 项目文件、库大小监控

背景

项目回归过程中,发现生成的包体积太大了,于是想检查下是那些库类占用的内存过大,并对内存占用过大的文件进行代码优化。优化过程中我们需要知道Link Map File文件(后面会给出Link Map File的解释)。

Shell坏境配置

笔者使用的Shell进行检测,由于脚本文件需要用到字典变量,但是字典变量的声明是Bash Shell版本是4.0以上,所以还需要对Bash Shell版本进行升级。

系统中使用的Shell

$ echo $SHELL
/bin/bash

查看系统中 Bash Shell 的版本

#方式一
$ bash -version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

#方式二
$ echo $BASH_VERSION
3.2.57(1)-release

需要版本到4.0以上,所以我们需要升级下Bash Shell版本

# 下载方式一
$ wget ftp://mirrors.ustc.edu.cn/gnu/bash/bash-4.2.tar.gz
# 下载方式二
$ brew install bash

# 解压后会在当前目录下生成一个bash-4.2目录
$ tar zxvf bash-4.2.tar.gz
# 进入目录bash-4.2
$ cd bash-4.2
# 准备配置configure
$ ./configure --prefix=/usr/local/bash4.2
# 编译
$ make
# 安装
$ make install
# 新安装的 Bash shell 为了设置成默认shell,需将其添加到/etc/shells文件。(需root身份编辑)
$ sudo echo "/usr/local/bash4.2/bin/bash" >> /etc/shells

# 设置默认Shell
$ chsh -s /usr/local/bin/bash
# chsh命令仅修改当前用户的默认shell。如果想修改root用户
$ sudo chsh -s /usr/local/bin/bash

注意

由于没有修改Bash的默认版本,而是安装了新版并将其设置为默认。Bash的两个版本并存:

/bin/bash:旧版
/usr/local/bash4.2/bin/bash:新版

在shell脚本中,我们经常在开头写一行Shebang,如下:

#!/bin/bash
echo $BASH_VERSION
注意,这一行Shebang明确指定了旧版本Bash。运行时就会调用旧版本的Bash执行(脚本输出显示,例如3.2.57(1)-release)。

大多数情况下,这可能没问题。如果想明确使用新版本Bash,修改shebang如下:

#!//usr/local/bash4.2/bin/bash
echo $BASH_VERSION
现在输出类似4.2.0(1)-release。但要注意,该方案不可移植,可能无法在其他系统上运行。因为其他系统可能没有位于/usr/local/bin/bash的shell(而/bin/bash基本是标准)。

要两全其美,修改shebang如下:

#!/usr/bin/env bash
echo $BASH_VERSION
这是shebang的推荐格式。原理是检查PATH并使用第一个找到的bash可执行文件作为脚本的解释器。如果新版的目录先于旧版(是默认版本),则将使用新版,并且脚本的输出类似4.2.0(1)-release。

Link Map File的生成以及结构

Link Map File中文直译为链接映射文件,它是在Xcode生成可执行文件的同时生成的链接信息文件,用于描述可执行文件的构造部分,包括了代码段和数据段的分布情况。Xcode在生成可执行文件的时候默认情况下不生成该文件,需要开发者手动设置Target --> Build Setting --> Write Link Map File为YES:
iOS 项目文件、库大小监控_第1张图片

# Path: /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Products/Debug-iphonesimulator/DetectTool.app/DetectTool
//	Path是可执行文件的路径

# Arch: x86_64
//	Arch指代架构类型。

# Object files:
[  0] linker synthesized
[  1] /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Intermediates.noindex/DetectTool.build/Debug-iphonesimulator/DetectTool.build/DetectTool.app-Simulated.xcent
[  2] /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Intermediates.noindex/DetectTool.build/Debug-iphonesimulator/DetectTool.build/Objects-normal/x86_64/ViewController.o
[  3] /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Intermediates.noindex/DetectTool.build/Debug-iphonesimulator/DetectTool.build/Objects-normal/x86_64/AppDelegate.o
[  4] /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Intermediates.noindex/DetectTool.build/Debug-iphonesimulator/DetectTool.build/Objects-normal/x86_64/main.o
[  5] /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Intermediates.noindex/DetectTool.build/Debug-iphonesimulator/DetectTool.build/Objects-normal/x86_64/SceneDelegate.o
[  6] /Users/dafyit/Library/Developer/Xcode/DerivedData/DetectTool-gqssxoqjthidklfikbryscecknjr/Build/Intermediates.noindex/DetectTool.build/Debug-iphonesimulator/DetectTool.build/Objects-normal/x86_64/DetectCodeTool.o
[  7] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.2.sdk/System/Library/Frameworks//Foundation.framework/Foundation.tbd
[  8] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.2.sdk/usr/lib/libobjc.tbd
[  9] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.2.sdk/System/Library/Frameworks//UIKit.framework/UIKit.tbd
//	Object Files 可执行文件里所有的obj以及tbd。前面的[0]、[1].....代表对文件的编号。

# Sections:
# Address	Size    	Segment	Section
0x100000C80	0x0000073E	__TEXT	__text
0x1000013BE	0x00000042	__TEXT	__stubs
0x100001400	0x0000007E	__TEXT	__stub_helper
0x10000147E	0x00000DA6	__TEXT	__objc_methname
0x100002224	0x0000007F	__TEXT	__objc_classname
0x1000022A3	0x00000ADA	__TEXT	__objc_methtype
0x100002D7D	0x000000B2	__TEXT	__cstring
0x100002E30	0x0000000A	__TEXT	__ustring
0x100002E3A	0x0000017A	__TEXT	__entitlements
0x100002FB4	0x00000048	__TEXT	__unwind_info
0x100003000	0x00000018	__DATA_CONST	__got
0x100003018	0x000000A0	__DATA_CONST	__cfstring
0x1000030B8	0x00000020	__DATA_CONST	__objc_classlist
0x1000030D8	0x00000020	__DATA_CONST	__objc_protolist
0x1000030F8	0x00000008	__DATA_CONST	__objc_imageinfo
0x100004000	0x00000058	__DATA	__la_symbol_ptr
0x100004058	0x000013D0	__DATA	__objc_const
0x100005428	0x00000048	__DATA	__objc_selrefs
0x100005470	0x00000030	__DATA	__objc_classrefs
0x1000054A0	0x00000008	__DATA	__objc_superrefs
0x1000054A8	0x00000008	__DATA	__objc_ivar
0x1000054B0	0x00000140	__DATA	__objc_data
0x1000055F0	0x00000188	__DATA	__data
//	Mach-O文件中的虚拟地址最终会被映射到物理地址上,这些地址会被分为不同的段类型:_ _ TEXT 、_ _ DATA以及_ _ LINKEDIT等。各个段的含义如下:
	_ _ TEXT包含了被执行的代码。这些代码是只读、可执行
	_ _ DATA包含了包含了将会被更改的数据,例如全局变量、静态变量等,可读写,但是不可执行
	_ _ LINKEDIT 包含了加载程序的元数据,比如函数名称和地址,只读。

# Symbols:
# Address	Size    	File  Name
0x100000C80	0x00000080	[  2] -[ViewController viewDidLoad]
0x100000D00	0x00000080	[  3] -[AppDelegate application:didFinishLaunchingWithOptions:]
0x100000D80	0x00000120	[  3] -[AppDelegate application:configurationForConnectingSceneSession:options:]
0x100000EA0	0x0000006C	[  3] -[AppDelegate application:didDiscardSceneSessions:]
0x100000F10	0x00000090	[  4] _main
0x100000FA0	0x000000A0	[  5] -[SceneDelegate scene:willConnectToSession:options:]
0x100001040	0x00000040	[  5] -[SceneDelegate sceneDidDisconnect:]
0x100001080	0x00000040	[  5] -[SceneDelegate sceneDidBecomeActive:]
0x1000010C0	0x00000040	[  5] -[SceneDelegate sceneWillResignActive:]
0x100001100	0x00000040	[  5] -[SceneDelegate sceneWillEnterForeground:]
0x100001140	0x00000040	[  5] -[SceneDelegate sceneDidEnterBackground:]
0x100001180	0x00000020	[  5] -[SceneDelegate window]
0x1000011A0	0x00000040	[  5] -[SceneDelegate setWindow:]
0x1000011E0	0x00000033	[  5] -[SceneDelegate .cxx_destruct]
0x100001220	0x00000190	[  6] -[DetectCodeTool printSource]
0x1000013B0	0x0000000E	[  6] -[DetectCodeTool cjh_123456]
...
//	根据Sections的起始地址,可以将Symbols分为Sections个数的组,例如0x100001730到0x100001A64之间,就是 _ _ test代码区。
	Symbols包含的信息有:
	Address:起始地址
	Size:所占内存大小,这里使用16进制表示。
	File:该Name所在的文件编号,也就是Object files部分的中括号的数字,例如-[ViewController viewDidLoad]对应的文件编号为2,根据Object files部分可以看到所属的文件为:ViewController.o。这样可以计算某个o文件所占内存的大小。只需要把Symbols中编号为o编号Symbols累加统计即可。
	Name:就是该Sybmols的名称。

# Dead Stripped Symbols:
#        	Size    	File  Name
<> 	0x00000018	[  2] CIE
<> 	0x00000018	[  3] CIE
<> 	0x00000018	[  4] CIE
<> 	0x00000009	[  5] literal string: NSObject
<> 	0x00000009	[  5] literal string: isEqual:
<> 	0x00000006	[  5] literal string: class
<> 	0x00000005	[  5] literal string: self

通过分析上述Link Map File文件,可以很容易匹配到各个可执行文件以及类库tbd的大小。
iOS 项目文件、库大小监控_第2张图片

资源脚本链接

【参考链接】

http://c.biancheng.net/view/741.html
https://www.jianshu.com/p/905d178f433c
https://www.jianshu.com/p/f003df0d0861

你可能感兴趣的:(iOS,Linux)