iOS底层--对象原理解析
2021-07-16 本文已影响0人
iOS心安
学习资料
指针地址和内存地址
YYObjet *p1 = [YYObjet alloc];
YYObjet *p2 = [p1 init];
YYObjet *p3 = [p1 init];
YYObjet *p4 = [YYObjet alloc];
NSLog(@"%@-%p-%p",p1,p1,&p1);
NSLog(@"%@-%p-%p",p2,p2,&p2);
NSLog(@"%@-%p-%p",p3,p3,&p3);
NSLog(@"%@-%p-%p",p4,p4,&p4);
<YYObjet: 0x6000025ec780>-0x6000025ec780-0x7ffeef1a1068
<YYObjet: 0x6000025ec780>-0x6000025ec780-0x7ffeef1a1060
<YYObjet: 0x6000025ec780>-0x6000025ec780-0x7ffeef1a1058
<YYObjet: 0x6000025ec7b0>-0x6000025ec7b0-0x7ffeef1a1050
复制代码
通过对比得到:
- p1,p2,p3 对象内存地址相同但是指针地址不同
- p4 和 p1,p2,p3 对象内存地址和指针地址都是不同
alloc
开辟内存空间,init
并没有开辟内存的操作,通过init的源码可以直观的看的出来。
底层探索的三种方法
1.符号断点
操作步骤
Jun-20-2021 12-02-53.gif- xcode 自带调试工具:
Ctrl
+Step into
- 加入符号断点
libobjc.A.dylib objc_alloc:
得到结果
image.png2.汇编
Jun-20-2021 10-04-34.gif3.符号断点 确定未知
- 简单来说:因为我们已经确定会调用
alloc
,所有直接对其加符号断点
得到结果
image.png通过以上三种调试方式,断点断在libobjc.A.dylib。可以在苹果开源网站下载对应的开源源码,对应的配置流程工程网上也有很多,可以下载调试[开车链接],更多的关注alloc的创建流程。
alloc 创建流程
通过流程跟踪,发现最终调用了 _class_createInstanceFromZone
[图片上传失败...(image-a4807f-1626418940051)]
可以用流程图更加清晰的表达
未命名文件 (2).png_class_createInstanceFromZone
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
int construct_flags = OBJECT_CONSTRUCT_NONE,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
ASSERT(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size;
size = cls->instanceSize(extraBytes); //计算内存大小(编译时期)
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (zone) {
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size); //开辟内存空间
}
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
if (!zone && fast) {
obj->initInstanceIsa(cls, hasCxxDtor);//初始化isa和cls绑定
} else {
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (fastpath(!hasCxxCtor)) {
return obj;
}
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
return object_cxxConstructFromClass(obj, cls, construct_flags);
}
复制代码
instanceSize
inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}
// 计算大小
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;// 十六字节对齐
return size;
}
复制代码
fastInstanceSize
size_t fastInstanceSize(size_t extra) const
{
ASSERT(hasFastInstanceSize(extra));
if (__builtin_constant_p(extra) && extra == 0) {
return _flags & FAST_CACHE_ALLOC_MASK16;
} else {
size_t size = _flags & FAST_CACHE_ALLOC_MASK;
// remove the FAST_CACHE_ALLOC_DELTA16 that was added
// by setFastInstanceSize
return align16(size + extra - FAST_CACHE_ALLOC_DELTA16); //字节对齐
}
}
复制代码
-
align16
16字节对齐
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
以10为例:
align16(10){
=(10 + size_t(15)) & ~size_t(15)
=(10 + 15)& ~ 15
= 25 & ~ 15
= 11001 & ~ 01111 //转化为二进制
= 11001 & 10000
= 10000 (十进制:16)
}