入门
Q isa
8字节
unsigned long
nonpointer : 第一位,是否对isa指针开启指针优化,0:纯isa指针,1: 不止是类对象地址,isa中包含了类信息、对象的引用计数等
has_assoc :第二位,关联对象标志位,0没有,1存在
has_cxx_dtor : 该对象是否有c++或者Objc的析构器,如果有析构函数,则需要做析构逻辑,如果没有,则可以更快的释放对象
shiftcls : 存储类指针的值,开启指针优化的情况下,在arm64架构中有32位用来存储类指针
magic : 用于调试器判断当前对象是真的对象还是没有初始化的空间
weakly_referenced : 指对象是否被指向或者曾经指向一个ARC的弱变量,没有弱引用的对象可以更快释放
deallocating : 标志对象是否正在释放内存
has_sidetable_rc : 当对象引用技术大于10时,则需要借用该变量存储进位
extra_rc : 当表示该对象的引用计数值,实际上是引用计数值减1,例如,如果对象的引用计数为10,那么extra_rc为9,如果引用计数大于10,则需要使用到上面的has_sidetable_rc
64位。
Q alloc
graph LR
alloc --> _objc_rootAlloc --> callAlloc --> class_createinstance --> A[_class_createInstanceFromZone] --> B[cls->instanceSize]
A --> C[calloc]
A --> d[obj->initInstanceIsa]
Q mian
dyld start:
Q 对象 alloc 执行过程
-> 0x102c85cd8 <+72>: callq 0x102c86372 ; symbol stub for: objc_alloc
-> 0x102c86372 <+0>: jmpq *0x5ca0(%rip) ; (void *)0x00007fff201a0ca4: objc_alloc
libobjc.A.dylib`objc_alloc:
libobjc.A.dylib`objc_msgSend:
001-alloc&init探索`-[ViewController viewDidLoad]:
libobjc.A.dylib`objc_retain:
libobjc.A.dylib`objc_object::sidetable_retain:
libobjc.A.dylib`objc_object::sidetable_retain:
libobjc.A.dylib`os_unfair_lock_lock_with_options:
-> 0x7fff201a303c <+0>: jmpq *0x5fe7b38e(%rip) ; (void *)0x00007fff6da22040: os_unfair_lock_lock_with_options
libsystem_platform.dylib`os_unfair_lock_lock_with_options:
libobjc.A.dylib`+[NSObject alloc]:
-> 0x7fff2019ee22 <+0>: jmp 0x7fff2019ee46 ; _objc_rootAlloc
libobjc.A.dylib`_objc_rootAlloc:
0x7fff2019ee4f <+9>: jmp 0x7fff20198d44 ; _objc_rootAllocWithZone
0x7fff2019ee54 <+14>: movq 0x6631c6fd(%rip), %rsi ; "allocWithZone:"
0x7fff2019ee5d <+23>: jmpq *0x5fe7f2dd(%rip) ; (void *)0x00007fff201833c0: objc_msgSend
libobjc.A.dylib`_objc_rootAllocWithZone:
0x7fff20198d64 <+32>: callq 0x7fff201a2f70 ; symbol stub for: calloc
0x7fff20198db7 <+115>: jmp 0x7fff201a27d1 ; _objc_callBadAllocHandler
0x7fff20198dcb <+135>: jmp 0x7fff20186dab ; object_cxxConstructFromClass
libsystem_malloc.dylib`calloc:
0x7fff2016d48e <+6>: leaq 0x66347b6b(%rip), %rdi ; virtual_default_zone
0x7fff2016d49a <+18>: jmp 0x7fff2016ce44 ; _malloc_zone_calloc
libsystem_malloc.dylib`_malloc_zone_calloc:
0x7fff2016ce5e <+26>: movb 0x6634e547(%rip), %r14b ; malloc_tracing_enabled
0x7fff2016ce6a <+38>: cmpl $0x0, 0x6634e53f(%rip) ; malloc_quarantine_enabled + 1
0x7fff2016ce82 <+62>: movq 0x6634e517(%rip), %rax ; malloc_logger
libsystem_malloc.dylib`_malloc_zone_calloc:
Q libobjc.A.dylib 动态库
- 代码断点
- 符号断点
- 汇编
Q 自定义打印
#ifdef DEBUG
#define JJNSLog(format, ...) printf("%s\n", [[NSString stringWithFormat:format, ## __VA_ARGS__] UTF8String]);
#else
#define JJNSLog(format, ...);
#endif
Q LLDB
%p打印地址po打印对象x/4gx object4个16进制p/t 0x011d8001000086c12进制p/o 0x011d8001000086c18进制p/d 0x011d8001000086c110进制memory read/数量格式字节数 内存地址读取内存memory write 0x0000010 10修改内存中的值
Q 字节大小
- b byte 1字节
- h half word 2字节
- w word 4字节
- g giant word 8字节
Q 读寄存器
register read x0
Q x0
x0 : 第一个存储地方,也是返回地方;
Q alloc 原理
+ (id)alloc {
return _objc_rootAlloc(self);
}
// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
if (slowpath(checkNil && !cls)) return nil;
#if __OBJC2__
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
// No alloc/allocWithZone implementation. Go straight to the allocator.
// fixme store hasCustomAWZ in the non-meta class and
// add it to canAllocFast's summary
if (fastpath(cls->canAllocFast())) {
// No ctors, raw isa, etc. Go straight to the metal.
bool dtor = cls->hasCxxDtor();
id obj = (id)calloc(1, cls->bits.fastInstanceSize());
if (slowpath(!obj)) return callBadAllocHandler(cls);
obj->initInstanceIsa(cls, dtor);
return obj;
}
else {
// Has ctor or raw isa or something. Use the slower path.
id obj = class_createInstance(cls, 0);
if (slowpath(!obj)) return callBadAllocHandler(cls);
return obj;
}
}
#endif
// No shortcuts available.
if (allocWithZone) return [cls allocWithZone:nil];
return [cls alloc];
}
// Replaced by ObjectAlloc
+ (id)allocWithZone:(struct _NSZone *)zone {
return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone);
}
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
{
id obj;
#if __OBJC2__
// allocWithZone under __OBJC2__ ignores the zone parameter
(void)zone;
obj = class_createInstance(cls, 0);
#else
if (!zone) {
obj = class_createInstance(cls, 0);
}
else {
obj = class_createInstanceFromZone(cls, 0, zone);
}
#endif
if (slowpath(!obj)) obj = callBadAllocHandler(cls);
return obj;
}
graph LR
alloc --> _objc_rootAlloc --> callAlloc --> A{hasCustomAWZ}
A --> |N|B{callAllocFast} --> |Y|E[calloc obj->initInstanceIsa]
A --> |Y|C[allocWithZone] --> _objc_rootAllocWithZone --> D{zone}
B --> |N|F[class_createInstance] --> H
D --> |N|F
D --> |N|K[initIsa calloc]
D --> |Y|J[class_createInstanceFromZone] --> H[_class_createInstanceFromZone]
D --> |Y|H[malloc_zone_calloc] --> W[obj->initIsa]
H --> I{!zone && fast} --> |N|D
I --> |Y|E
D --> O[malloc_zone_calloc initIsa]
Q 消息转发机制
- 编译阶段
/*
不带参数:objc_msgSend(receiver,selector)
带参数:objc_msgSend(recevier,selector,org1,org2,…)
*/
- 运行时阶段
/*
1. 如果selector、target两个都是有效的,那就开始查找这个类的 IMP,先从 cache 里面找,若可以找得到就跳到对应的函数去执行。
2. 如果在cache里找不到就找一下方法列表methodLists。
3. 如果methodLists找不到,就到超类的方法列表里寻找,一直找,直到找到NSObject类为止。
4. 如果还找不到,Runtime就提供了如下三种方法来处理:动态方法解析、消息接受者重定向、消息重定向
*/
Q NSProxy
/*
NSProxy 是一个抽象基类,它是为`一些作为对象的替身或者并不存在的对象`定义的API。
可以通过继承 NSProxy,并重写下面这两个方法来实现消息转发到另一个实例中。
*/
- (void)forwardInvocation:(NSInvocation *)invocation;
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
Q calloc
calloc 是对象的创建者, 指针8字节, class是一个对象,对象是一个指针。对象需要开辟多少内存空间?答案是8字节。
alignedInstanceSize() 是字节对齐函数,返回一个 word_align()函数
unalignedInstanceSize() 是没有字节对齐的函数,返回一个 data()->ro->instanceSize;
objc_class 是一个结构体,继承 objc_object
计算内存
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
内存算法:
// X :值是8,因为是指针,上面传值过来的指针
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
64位计算器 Unicode
// WORD_MASK :值是7
// 7+8=15
// 0000 0000 0000 0111 7
// 1111 1111 1111 1000 ~7 (NOR)
// 0000 0000 0000 1111 15
// 0000 0000 0000 1000 8
// 1111 1111 1111 1000 & 0000 0000 0000 1111 = 0000 0000 0000 1000
// 8 的倍数对齐
size :对象需要的内存空间 8的倍数 - 8字节对齐, 最少16字节,提高字节读取的性能。(以空间换时间)
给对象不赋值,是一个假的内存地址。
Student *s = [Student alloc];
s.name = "xiaohua";
s.age = 19;
s.height = 1.61;
// x p 以16进制打印对象的地址空间,第一个地址是 isa ,之后的地址是 name age height
// ios 是一个小端模式,
// x/4xg p
进阶
Q 底层探索方式
- 汇编分析
- LLDB分析
- 源码分析
Q objc4-838
Q 允许任何来源
zone 的初始化
static void *
default_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size)
{
zone = runtime_default_zone();
return zone->calloc(zone, num_items, size);
}
// p zone->calloc
// nano_calloc
static void *
nano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)
{
size_t total_bytes;
if (calloc_get_size(num_items, size, 0, &total_bytes)) {
return NULL;
}
if (total_bytes <= NANO_MAX_SIZE) {
void *p = _nano_malloc_check_clear(nanozone, total_bytes, 1);
if (p) {
return p;
} else {
/* FALLTHROUGH to helper zone */
}
}
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
return zone->calloc(zone, 1, total_bytes);
}
Q 编译优化的作用
- 编译时间:load 耗时操作
- 链接时间
- 运行时间
- 空闲时间
Q obj->initInstanceIsa()
obj 指针关联类的函数, allocWithZone()
实践
Q alloc
- _objc_rootAlloc(Class cls)
- objc_alloc(Class cls)
Q objc_alloc
/**
系统符号表绑定: sel - imp,相当于书和目录的对应关系。函数的实现需要通过找到sel对象对应的imp,通过imp找到函数的实现。
macho - 绑定symbol - sel_alloc - objc_alloc
callalloc - [cls alloc]
objc_alloc 只走一次,修复类
imp 是函数指针, @implementation
*/
static void
fixupMessageRef(message_ref_t *msg)
msg->imp = (IMP)&objc_alloc;
Q clang 编译
clang -rewrite-objc main.m -o main.cpp
@encode
struct NSObject_IMPL {
struct NSObject_IMPL NSObject_IVARS;
}
Q RunLoop
保证线程在没有消息的时候休眠,在有消息时候唤醒,以提高程序性能。机制是依靠系统内核来完成的,苹果操作系统的核心组件 Darwin 中的 Mach.
Q 事件响应过程
苹果注册一个Source1 (基于 mach port) 用来接收系统事件,其回调函数为
__IOHIDEventSystemClientQueueCallback()
IOKit.framework
Q 手势识别过程
__UIGestureRecognizerUpdateObserver() 回调函数处理相应处理
Q RunLoop页面渲染
beforeWaiting 进行绘制
display: 异步绘制
Backing Store 获取图形上下文
GPU 图层渲染,纹理合成
Q 事件传递与视图响应链
hitTest:
pointInside:
Q 图像显示原理
- CPU
- Layout
- Display
- Prepare
- Commit
- GPU
- 顶点着色
- 图元装配
- 光栅化
- 片段着色
- 片段处理
Q UI 卡顿
Vsync 垂直同步信号 16.7ms/帧
Q UI 绘制原理
[self.layer.delegate displayLayer: ]
bitmap
Q 离屏渲染
layer.shouldRasterize = YES;
On-Screen Rendering:当前屏幕渲染,指的是 GPU 的渲染操作是在当前用于显示的屏幕缓冲区中进行
Off-Screen Rendering:离屏渲染,分为 CPU 离屏渲染和 GPU 离屏渲染两种形式。GPU 离屏渲染指的是 GPU
在当前屏幕缓冲区外新开辟一个缓冲区进行渲染操作
应当尽量避免的则是 GPU 离屏渲染
Q YYModel 原理
- NSObject+YYModel.h
- YYModelPropertyMeta
- YYModelMeta
Q 哈希算法
- 负载均衡静态调度算法 1.轮询 2.随机 3.权重
- 平滑轮询加权
- 一致性哈希
- 最小活跃数算法
Q 性能优化
-
优化 App 电量:
- cpu
-
网络方面:
- ProtoBuf
Q Huffman 算法
致谢
- Cooci
- ibireme
- 更多开源框架的大神