[toc]
前言
2ab2ac029a0164f961729c31cc16bfd3在
iOS
程序中会用到很多系统的动态库,这些动态库都是动态加载的。所有iOS
程序共用一套系统动态库,在程序开始运行时才会开始链接动态库。
除了在项目设置里显式出现的动态库外,还会有一些隐式存在的动态库。例如
objc
和Runtime
所属的libobjc.dyld
和libSystem.dyld
,在libSystem
中包含常用的libdispatch(GCD)、libsystem_c(C语言基础库)、libsystem_blocks(Block)等。
使用动态库的优点:
- 防止重复。
iOS
系统中所有App
公用一套系统动态库,防止重复的内存占用。 - 减少包体积。因为系统动态库被内置到
iOS
系统中,所以打包时不需要把这部分代码打进去,可以减小包体积。 - 动态性。因为系统动态库是动态加载的,所以可以在更新系统后,将动态库换成新的动态库。
加载过程
在应用程序启动后,由dyld(the dynamic link editor)进行程序的初始化操作。大概流程就像下面列出的步骤,其中第3、4、5步会执行多次,在ImageLoader加载新的image进内存后就会执行一次。
- 在引用程序启动后,由
dyld
将应用程序加载到二进制中,并完成一些文件的初始化操作。 -
Runtime
向dyld
中注册回调函数。 - 通过
ImageLoader
将所有image
加载到内存中。 -
dyld
在image
发生改变时,主动调用回调函数。 -
Runtime
接收到dyld
的函数回调,开始执行map_images、load_images
等操作,并回调+load
方法。 - 调用
main()
函数,开始执行业务代码。
ImageLoader
是image
的加载器,image
可以理解为编译后的二进制。
下面是在Runtime
的map_images
函数打断点,观察回调情况的汇编代码。可以看出,调用是由dyld
发起的,由ImageLoader
通知dyld
进行调用。
动态加载
一个OC程序可以在运行过程中动态加载和链接新类或Category,新类或Category会加载到程序中,其处理方式和其他类是相同的。动态加载还可以做许多不同的事,动态加载允许应用程序进行自定义处理。
OC提供了
objc_loadModules
运行时函数,执行Mach-O中模块的动态加载,在上层NSBundle
对象提供了更简单的访问API。
map images
在Runtime
加载时,会调用_objc_init
函数,并在内部注册三个函数指针。其中map_images
函数是初始化的关键,内部完成了大量Runtime
环境的初始化操作。
在
map_images
函数中,内部也是做了一个调用中转。然后调用到map_images_noloc
k函数,内部核心就是_read_images
函数。
源码分析
// .... 各种init
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
}
void map_images(unsigned count, const char * const paths[],
const struct mach_header * const mhdrs[])
{
rwlock_writer_t lock(runtimeLock);
return map_images_nolock(count, paths, mhdrs);
}
void map_images_nolock(unsigned mhCount, const char * const mhPaths[],
const struct mach_header * const mhdrs[])
{
if (hCount > 0) {
_read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
}
}
read_images函数内部的逻辑
先整体梳理一遍_read_images函数内部的逻辑:
- 加载所有类到类的
gdb_objc_realized_classes
表中。 - 对所有类做重映射。
- 将所有SEL都注册到
namedSelectors
表中。 - 修复函数指针遗留。
- 将所有
Protocol
都添加到protocol_map
表中。 - 对所有
Protocol
做重映射。 - 初始化所有非懒加载的类,进行
rw、ro
等操作。 - 遍历已标记的懒加载的类,并做初始化操作。
- 处理所有
Category
,包括Class
和Meta Class
。 - 初始化所有未初始化的类。
源码
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses)
{
header_info *hi;
uint32_t hIndex;
size_t count;
size_t I;
Class *resolvedFutureClasses = nil;
size_t resolvedFutureClassCount = 0;
static bool doneOnce;
TimeLogger ts(PrintImageTimes);
#define EACH_HEADER \
hIndex = 0; \
hIndex < hCount && (hi = hList[hIndex]); \
hIndex++
if (!doneOnce) {
doneOnce = YES;
// 实例化存储类的哈希表,并且根据当前类数量做动态扩容
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
}
// 由编译器读取类列表,并将所有类添加到类的哈希表中,并且标记懒加载的类并初始化内存空间
for (EACH_HEADER) {
if (! mustReadClasses(hi)) {
continue;
}
bool headerIsBundle = hi->isBundle();
bool headerIsPreoptimized = hi->isPreoptimized();
/** 将新类添加到哈希表中 */
// 从编译后的类列表中取出所有类,获取到的是一个classref_t类型的指针
classref_t *classlist = _getObjc2ClassList(hi, &count);
for (i = 0; i < count; i++) {
// 数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop等系统类,例如CF、Fundation、libdispatch中的类。以及自己创建的类
Class cls = (Class)classlist[I];
// 通过readClass函数获取处理后的新类,
//内部主要操作ro和rw结构体(需要后期处理)
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
// 初始化所有懒加载的类需要的内存空间
if (newCls != cls && newCls) {
// 将懒加载的类添加到数组中
resolvedFutureClasses = (Class *)
realloc(resolvedFutureClasses,
(resolvedFutureClassCount+1) * sizeof(Class));
resolvedFutureClasses[resolvedFutureClassCount++] = newCls;
}
}
}
// 将未映射Class和Super Class重映射,被remap的类都是非懒加载的类
if (!noClassesRemapped()) {
for (EACH_HEADER) {
// 重映射Class,注意是从_getObjc2ClassRefs函数中取出类的引用
Class *classrefs = _getObjc2ClassRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[I]);
}
// 重映射父类
classrefs = _getObjc2SuperRefs(hi, &count);
for (i = 0; i < count; i++) {
remapClassRef(&classrefs[I]);
}
}
}
// 将所有SEL都注册到哈希表中,是另外一张哈希表
static size_t UnfixedSelectors;
sel_lock();
for (EACH_HEADER) {
if (hi->isPreoptimized()) continue;
bool isBundle = hi->isBundle();
SEL *sels = _getObjc2SelectorRefs(hi, &count);
UnfixedSelectors += count;
for (i = 0; i < count; i++) {
const char *name = sel_cname(sels[i]);
// 注册SEL的操作
sels[i] = sel_registerNameNoLock(name, isBundle);
}
}
// 修复旧的函数指针调用遗留
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
if (count == 0) continue;
for (i = 0; i < count; i++) {
// 内部将常用的alloc、objc_msgSend等函数指针进行注册,并fix为新的函数指针
fixupMessageRef(refs+i);
}
}
// 遍历所有协议列表,并且将协议列表加载到Protocol的哈希表中
for (EACH_HEADER) {
extern objc_class OBJC_CLASS_$_Protocol;
// cls = Protocol类,所有协议和对象的结构体都类似,isa都对应Protocol类
Class cls = (Class)&OBJC_CLASS_$_Protocol;
assert(cls);
// 获取protocol哈希表
NXMapTable *protocol_map = protocols();
bool isPreoptimized = hi->isPreoptimized();
bool isBundle = hi->isBundle();
// 从编译器中读取并初始化Protocol
protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map,
isPreoptimized, isBundle);
}
}
// 修复协议列表引用,优化后的images可能是正确的,但是并不确定
for (EACH_HEADER) {
// 需要注意到是,下面的函数是_getObjc2ProtocolRefs,和上面的_getObjc2ProtocolList不一样
protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
for (i = 0; i < count; i++) {
remapProtocolRef(&protolist[I]);
}
}
// 实现非懒加载的类,对于load方法和静态实例变量
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
addClassTableEntry(cls);
if (!cls) continue;
addClassTableEntry(cls);
// 实现所有非懒加载的类(实例化类对象的一些信息,例如rw)
realizeClassWithoutSwift(cls);
}
}
// 遍历resolvedFutureClasses数组,实现所有懒加载的类
if (resolvedFutureClasses) {
for (i = 0; i < resolvedFutureClassCount; i++) {
// 实现懒加载的类
realizeClass(resolvedFutureClasses[I]);
resolvedFutureClasses[i]->setInstancesRequireRawIsa(false/*inherited*/);
}
free(resolvedFutureClasses);
}
// 发现和处理所有Category
for (EACH_HEADER) {
// 外部循环遍历找到当前类,查找类对应的Category数组
category_t **catlist =
_getObjc2CategoryList(hi, &count);
bool hasClassProperties = hi->info()->hasCategoryClassProperties();
// 内部循环遍历当前类的所有Category
for (i = 0; i < count; i++) {
category_t *cat = catlist[I];
Class cls = remapClass(cat->cls);
// 首先,通过其所属的类注册Category。如果这个类已经被实现,则重新构造类的方法列表。
bool classExists = NO;
if (cat->instanceMethods || cat->protocols
|| cat->instanceProperties)
{
// 将Category添加到对应Class的value中,value是Class对应的所有category数组
addUnattachedCategoryForClass(cat, cls, hi);
// 将Category的method、protocol、property添加到Class
if (cls->isRealized()) {
remethodizeClass(cls);
classExists = YES;
}
}
// 这块和上面逻辑一样,区别在于这块是对Meta Class做操作,而上面则是对Class做操作
// 根据下面的逻辑,从代码的角度来说,是可以对原类添加Category的
if (cat->classMethods || cat->protocols
|| (hasClassProperties && cat->_classProperties))
{
addUnattachedCategoryForClass(cat, cls->ISA(), hi);
if (cls->ISA()->isRealized()) {
remethodizeClass(cls->ISA());
}
}
}
}
// 初始化从磁盘中加载的所有类,发现Category必须是最后执行的
// 从runtime,DebugNonFragileIvars字段一直是-1,所以不会进入这个方法中
if (DebugNonFragileIvars) {
realizeAllClasses();
}
#undef EACH_HEADER
}
源码简化
void _read_images {
// 第一次进来 - 开始创建表
// gdb_objc_realized_classes : 所有类的表 - 包括实现的和没有实现的
// allocatedClasses: 包含用objc_allocateClassPair分配的所有类(和元类)的表。(已分配)
if (!doneOnce) {
doneOnce = YES;
// namedClasses
// Preoptimized classes don't go in this table.
// 4/3 is NXMapTable's load factor
int namedClassesSize =
(isPreoptimized() ? unoptimizedTotalClasses : totalClasses) * 4 / 3;
gdb_objc_realized_classes =
NXCreateMapTable(NXStrValueMapPrototype, namedClassesSize);
allocatedClasses = NXCreateHashTable(NXPtrPrototype, 0, nil);
}
// 读取所有类的列表
for (EACH_HEADER) {
classref_t *classlist = _getObjc2ClassList(hi, &count);
}
// 获取所有的类引用
for (EACH_HEADER) {
Class *classrefs = _getObjc2ClassRefs(hi, &count);
}
// sel - 方法编号
for (EACH_HEADER) {
SEL *sels = _getObjc2SelectorRefs(hi, &count);
}
// 修复旧的objc_msgSend_fixup调用导致一些消息没有处理
for (EACH_HEADER) {
message_ref_t *refs = _getObjc2MessageRefs(hi, &count);
}
// 协议
for (EACH_HEADER) {
protocol_t **protolist = _getObjc2ProtocolList(hi, &count);
for (i = 0; i < count; i++) {
readProtocol(protolist[i], cls, protocol_map, isPreoptimized, isBundle);
}
}
// 修复协议重映射
// 获取所有的协议引用
for (EACH_HEADER) {
protocol_t **protolist = _getObjc2ProtocolRefs(hi, &count);
for (i = 0; i < count; i++) {
remapProtocolRef(&protolist[I]);
}
}
// 实现非惰性类(用于+ load方法和静态实例)
for (EACH_HEADER) {
classref_t *classlist = _getObjc2NonlazyClassList(hi, &count);
}
// 在CF基础上,实现未来类
if (resolvedFutureClasses) {
for (i = 0; i < resolvedFutureClassCount; i++) {
Class cls = resolvedFutureClasses[I];
if (cls->isSwiftStable()) {
_objc_fatal("Swift class is not allowed to be future");
}
realizeClassWithoutSwift(cls);
cls->setInstancesRequireRawIsa(false/*inherited*/);
}
free(resolvedFutureClasses);
}
// 分类
for (EACH_HEADER) {
category_t **catlist = _getObjc2CategoryList(hi, &count);
}
}
分析类的加载
数组中会取出OS_dispatch_queue_concurrent、OS_xpc_object、NSRunloop
等系统类,例如CF、Fundation、libdispatch
中的类。以及自己创建的类
通过readClass函数获取处理后的新类
addNamedClass(cls, mangledName, replacing); addClassTableEntry(cls);
这两个方法讲类加入到table
列表中 是一个hash
表
Class cls = (Class)classlist[I];
Class newCls = readClass(cls, headerIsBundle, headerIsPreoptimized);
readClass
Class newCls = popFutureNamedClass(mangledName)打断点调试发现并没有走这里所以rw不在此时负责
if (Class newCls = popFutureNamedClass(mangledName)) {
// This name was previously allocated as a future class.
// Copy objc_class to future class's struct.
// Preserve future's rw data block.
if (newCls->isAnySwift()) {
_objc_fatal("Can't complete future class request for '%s' "
"because the real class is too big.",
cls->nameForLogging());
}
class_rw_t *rw = newCls->data();
const class_ro_t *old_ro = rw->ro;
memcpy(newCls, cls, sizeof(objc_class));
rw->ro = (class_ro_t *)newCls->data();
newCls->setData(rw);
freeIfMutable((char *)old_ro->name);
free((void *)old_ro);
addRemappedClass(cls, newCls);
replacing = cls;
cls = newCls;
}
if (headerIsPreoptimized && !replacing) {
// class list built in shared cache
// fixme strict assert doesn't work because of duplicates
// assert(cls == getClass(name));
assert(getClassExceptSomeSwift(mangledName));
} else {
addNamedClass(cls, mangledName, replacing);
addClassTableEntry(cls);
}
实现非懒加载的类,对于load
方法和静态实例变量
for (EACH_HEADER) {
classref_t *classlist =
_getObjc2NonlazyClassList(hi, &count);
for (i = 0; i < count; i++) {
Class cls = remapClass(classlist[i]);
// printf("non-lazy Class:%s\n",cls->mangledName());
if (!cls) continue;
// hack for class __ARCLite__, which didn't get this above
#if TARGET_OS_SIMULATOR
if (cls->cache._buckets == (void*)&_objc_empty_cache &&
(cls->cache._mask || cls->cache._occupied))
{
cls->cache._mask = 0;
cls->cache._occupied = 0;
}
if (cls->ISA()->cache._buckets == (void*)&_objc_empty_cache &&
(cls->ISA()->cache._mask || cls->ISA()->cache._occupied))
{
cls->ISA()->cache._mask = 0;
cls->ISA()->cache._occupied = 0;
}
#endif
//已经添加过的类不会再次添加
addClassTableEntry(cls);
......
// 实现所有非懒加载的类(实例化类对象的一些信息,例如rw)
realizeClassWithoutSwift(cls);
realizeClassWithoutSwift
- 读取class的data() ro/rw的创建
//这个地方很重要
if (!cls) return nil;
if (cls->isRealized()) return cls;
assert(cls == remapClass(cls));
// fixme verify class is not in an un-dlopened part of the shared cache?
ro = (const class_ro_t *)cls->data();
if (ro->flags & RO_FUTURE) {
// This was a future class. rw data is already allocated.
rw = cls->data();
ro = cls->data()->ro;
cls->changeInfo(RW_REALIZED|RW_REALIZING, RW_FUTURE);
} else {
// Normal class. Allocate writeable class data.
rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
rw->ro = ro;
rw->flags = RW_REALIZED|RW_REALIZING;
cls->setData(rw);
}
- 父类 和元类的创建 这是一个递归 最后都会return nil;
supercls = realizeClassWithoutSwift(remapClass(cls->superclass));
metacls = realizeClassWithoutSwift(remapClass(cls->ISA()));
- 设置父类与元类的归属关系
// Update superclass and metaclass in case of remapping
cls->superclass = supercls;
cls->initClassIsa(metacls);
- .将此类链接到超类的子类列表 (看翻译)
// Connect this class to its superclass's subclass lists
if (supercls) {
addSubclass(supercls, cls);
} else {
addRootClass(cls);
}
realizeClassWithoutSwift->methodizeClass(cls);
通过mrthod_list_t property_list_t protocol_list_t 将属性 协议 方法 分类写入.
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
rw->methods.attachLists(&list, 1);
}
property_list_t *proplist = ro->baseProperties;
if (proplist) {
rw->properties.attachLists(&proplist, 1);
}
protocol_list_t *protolist = ro->baseProtocols;
if (protolist) {
rw->protocols.attachLists(&protolist, 1);
}
// Root classes get bonus method implementations if they don't have
// them already. These apply before category replacements.
if (cls->isRootMetaclass()) {
// root metaclass
//类方法级内部实现
addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
}
// Attach categories.
category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
attachCategories(cls, cats, false /*don't flush caches*/);
attachLists内部实现
- 多对多 直接扩容将数组插进去
- 只有一个直接加入
- 一对多 插在最前面
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
uint32_t oldCount = array()->count;//10
uint32_t newCount = oldCount + addedCount;//4
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
array()->count = newCount;// 10+4
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];
}
else {
// 1 list -> many lists
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)malloc(array_t::byteSize(newCount)));
array()->count = newCount;
if (oldList) array()->lists[addedCount] = oldList;
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
}
网友评论