OC对象原理
LLPerson *p1 = [LLPerson alloc];
LLPerson *p2 = [p1 init];
LLPerson *p3 = [p1 init];
NSLog(@"%@ - %p", p1, &p1);
NSLog(@"%@ - %p", p2, &p2);
NSLog(@"%@ - %p", p3, &p3);
alloc 已经创建了对象 init
alloc 实现 - 原理 - 源码实现
三种方式
libobjc.A.dylib
-
下断点
control + in - objc_alloc
-
下符号断点
libobjc.A.dylib +[NSObject alloc]
-
汇编
libobjc.A.dylib objc_alloc
源码地址:https://opensource.apple.com/
alloc 申请内存空间 - 给指针地址 LLPerson
register read x0 读取寄存器内容 返回的对象 - x0 储存地方
LLPerson 无属性 只含有isa 指针8字节
字节对齐 x + 7 & ~7 以8为倍数 以空间换取时间
size :
- 对象需要的内存空间 8的倍数 - 8字节对齐
- 最少16
打印地址:
x p1
x/4xg p1 每四位打印
内存值 - 内存对齐
8字节 0x00000012 - int 4 + 4
char 1 + 7
补充:
[NSbject alloc]会先走objc_alloc
方法 - sel(alloc) - imp(objc_alloc) - 函数实现
macho - 绑定symbol - sel_alloc - objc_alloc
callalloc - [cls alloc]
关于内存对齐的一个c语言结构题问题补充
struct LLStruct1 {
char a; // 1 + 7
double b; // 8
int c; // 4
short d; // 2 + 2
} MyStruct1;
struct LLStruct2 {
double b; // 8
int c; // 4
char a; // 1 + 1
short d; // 2
} MyStruct2;
MyStruct1 24个字节 1 + 7 + 8 + 4 + 2 + 2
MyStruct2 16个字节 8 + 4 + 1 + 1 + 2
LLPerson *p = [LLPerson alloc];
p.name = @"name"; // 8 NSString
p.age = 20; // 4 int
p.height = 188; // 8 long
p.hobby = @"男"; // 8 NSString
// isa -------- // 8 *
class_getInstanceSize 36 – 8 * 5 = 40 , class_getInstanceSize没有判断size < 16
对象申请的内存大小 和 系统开辟的大小 不一致
calloc 16字节对齐 size + 16 - 1(2^4 - 1) >> 4 << 4
前面8字节对齐 - 对象里面的属性
16字节对齐 - 对象
系统开辟 风险 - 内存连续
ISA
union 联合体内容补充
公用内存 - 联合体里面最大的那个
union {
char bits;
//位域
struct {
char front : 1;
char back : 1;
char left : 1;
char right : 1;
}
} _direction;
isa指针 联合体 位域 8字节 64位 存储优化
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h arm64
// uintptr_t nonpointer : 1; nonpointer: 表示是否对isa指针开启指针优化 0:纯isa指针,1:不止是类对象地址,isa中包含了类信息、对象的引用计数等
// uintptr_t has_assoc : 1; has_assoc: 关联对象标志位,0没有,1存在
// uintptr_t has_cxx_dtor : 1; has_cxx_dtor: 该对象是否有C++或者Objc的析构器,如果有析构函数,则需要做析构逻辑,如果没有,则可以更快的释放对象
// uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ shiftcls: 存储类指针的值,开启指针优化的情况下,在arm64架构中有33位用来存储类指针
// uintptr_t magic : 6; magic: 用于调试器判断当前对象是真的对象还是没有初始化的空间
// uintptr_t weakly_referenced : 1; weakly_referenced: 标志对象是否被指向或者曾经指向一个ARC的弱变量,没有弱引用的对象可以更快释放
// uintptr_t deallocating : 1; deallocating: 标示对象是否正在释放内存
// uintptr_t has_sidetable_rc : 1; has_sidetable_rc: 当对象引用计数大于10时,则需要借用该变量存储进位
// uintptr_t extra_rc : 19 ¸Uœ∑µ˚•™¶已;;在Aø extra_rc: 当表示该对象的引用计数值,实际上是引用计数减1,例如,如果对象的引用计数为10,那么ext怇
};
#endif
};
内存里 - 属性位置是会发生变化
对象第一个属性必然是isa (NSObject)
isa <-> cls isa关联类 isa & ISA_MASK
p/x 十六进制打印 p/t 二进制打印 p/o 八进制打印 p/d 十进制打印
对象可以创建多个
类在内存中只有一份
类的内存 第一个位置指向元类
对象 - 根据类实例化
类 - 系统创建
元类 - 系统编译时创建,编译器创建
对象 -> 类对象 -> 元类 -> 根元类 -> 根元类
NSObject 根类 -> 根元类
isa走位和继承关系:
对象的本质
对象 - 编译 - 结构体 父类的属性继承过来
当添加属性之后,会有对应的属性
同时,会生成相应的getter和setter方法
getter方法 函数实现 - LLPerson * self, SEL _cmd 两个隐藏参数 所以在willDidLoad
中可以拿到self
setter方法 objc_setProperty
method_list
@16@0:8 签名
@ 返回值 :id
@ 参数一类型 : id 0 - 7
: 参数二类型 : sel 8 - 15
- 结构体
- 属性 成员变量 getter setter
成员变量底层编译不会生成相应的setter和getter
属性 = 成员变量 + setter + getter
相关命令行:
编译底层源码: clang -rewrite-objc main.m -o main.cpp
存在UIKit系统其他动态库引用问题:clang -x objective-c -rewrite-objc -isysroot /Application/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk ViewController.m
xcrun xcode 命令:xcrun -sdk iphonesimulator clang -rewrite-objc ViewController.m
或 xcrun -sdk iphoneos clang -rewrite-objc ViewController.m