update: image source

This commit is contained in:
杭城小刘
2024-02-23 15:58:55 +08:00
parent fb51939f76
commit 6e47061735
22 changed files with 783 additions and 61 deletions

View File

@@ -10,7 +10,7 @@ NSTimer、CADisplayLink 的 基础 API `[NSTimer scheduledTimersWithTimeInterval
栈、堆、BSS、数据段、代码段
![](./../assets/iOS-MemoryLayout.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/iOS-MemoryLayout.png)
stack又称作堆栈用来存储程序的局部变量但不包括static声明的变量static修饰的数据存放于数据段中。除此之外在函数被调用时栈用来传递参数和返回值。栈内存地址越来越少
@@ -37,7 +37,7 @@ BSS段bss segment通常用来存储程序中未被初始化的全局变
代码段code segment编译之后的代码。通常是指用来存储程序可执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定并且内存区域通常属于只读某些架构也允许代码段为可写即允许修改程序。
![内存](./../assets/ram.png)
![内存](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ram.png)
上 Demo 验证
@@ -147,7 +147,7 @@ Demo1
运行该代码会 Crash报错信息如下
![](./../assets/TaggedPointerCrash.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/TaggedPointerCrash.png)
说明:一开始的报错信息只说坏内存访问,但是并没有显示具体的方法调用堆。想知道具体 Crash 原因还是需要看看堆栈比较方便。输入 bt 查看最后是由于 `objc_release` 方法造成 crash。
@@ -257,7 +257,7 @@ static inline bool _objc_isTaggedPointer(const void * _Nullable ptr)
tips某些对象虽然是 TaggedPointer 类型,但是打印 class 发现不是,猜测可能是系统用类簇隐藏了某些实现细节。比如下面
![](./../assets/NSTaggedPointerOfNSNumber.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/NSTaggedPointerOfNSNumber.png)
针对 NSNumber 的 TaggedPoniter 的 case查看 class 打印出 `__NSCFNumber`。但根据源码和内存高地址位分析确实是 TaggedPoniter。
@@ -826,7 +826,7 @@ void sel_init(size_t selrefCount){
在 gone 处加断点,利用 runtime 查看类中的方法信息
![](./../assets/cxx_destructDemo1.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/cxx_destructDemo1.png)
发现存在 `.cxx_destruct` 方法。
@@ -861,7 +861,7 @@ void sel_init(size_t selrefCount){
@end
```
![](./../assets/cxx_destructdemo3.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/cxx_destructdemo3.png)
Tips@property 会自动生成成员变量,另外类后面加 `{}` 在内部也可以加成员变量,假如成员变量是对象类型,比如 NSString则叫实例变量。
@@ -875,7 +875,7 @@ Tips@property 会自动生成成员变量,另外类后面加 `{}` 在内部
在 gone 的地方加断点,输入 `watchpoint set variable p->_name`,则会将 `_name` 实例变量加入 watchpoint当变量被修改时会触发断点可以看出从某个值变为 0x0也就是 nil。此时边上调用堆栈显示在 `objc_storestrong` 方法中,被设置为 nil.
![](./../assets/cxx_destructDemo2.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/cxx_destructDemo2.png)
### 深入 .cxx_destruct
@@ -1123,7 +1123,7 @@ class AutoreleasePoolPage {
- 每个 AutoreleasePoolPage 对象占用 4096 字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放 autorelease 对象的地址
- 所有的 AutoreleasePoolPage 对象通过**双向链表**的形式连接在一起。child 指向下一个对象parent 指向上一个对象
![](./../assets/autoreleasepool.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/autoreleasepool.png)
```objectivec
id * begin() {
@@ -1181,7 +1181,7 @@ int main(int argc, const char * argv[]) {
main 方法内部3个 autoreleasepool 底层怎么样工作的?
![](./../assets/AutoreleasePoolMoreItem.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/AutoreleasePoolMoreItem.png)
3个@auto releasepool 系统遇到第一个的时候底层就是初始化一个结构体 `__AtAutoreleasePool`,结构体构造方法内部调用 `AutoreleasePoolPage::push` 方法,系统给 AutoreleasePoolPage 真正保存 autorelease 对象的地方存储进一个 `POOL_BOUNDARY` 对象,然后储存 P1、P2 对象地址,遇到第二个则继续初始化结构体,调用 push 方法,存储一个` POOL_BOUNDARY` 对象,继续保存 P3遇到第三个则继续初始化结构体调用 push 方法,存储一个 `POOL_BOUNDARY` 对象,继续保存 P4。
@@ -1963,7 +1963,7 @@ static inline id *autoreleaseFast(id obj) {
每当进行一次`objc_autoreleasePoolPush`调用时runtime 向当前的 AutoreleasePoolPage 中 add 进一个`哨兵对象`值为0也就是个nil那么这一个page就变成了下面的样子
![](./../assets/autoreleasepool-push.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/autoreleasepool-push.png)
`objc_autoreleasePoolPush`的返回值正是这个哨兵对象的地址,被`objc_autoreleasePoolPop(哨兵对象)`作为入参,于是:
@@ -1981,7 +1981,7 @@ iOS 在主线程的 Runloop 中注册了2个 Observer
结合 RunLoop 运行图
![](./../assets/RunLoop-SourceCode.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/RunLoop-SourceCode.png)
- 01 通知 Observer 进入 Loop 会调用 `objc_autoreleasePoolPush`
@@ -2070,7 +2070,7 @@ NSHashMap、NSMapTable 都可以描述 key、value 的内存修饰。
这段代码运行会 crash信息如下
![](./../assets/NSErrorZombieCrash.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/NSErrorZombieCrash.png)
原因是 NSError 构造方法内部会加 autorelease。源码如下
@@ -2133,7 +2133,7 @@ MRC 下的 `[(id)(object) autorelease]` 等价于 ARC 下的 `id __autoreleasing
我写了个僵尸对象检测工具,效果如下
![](./../assets/ZombieSniffer.png)
![](https://github.com/FantasticLBP/knowledge-kit/raw/master/assets/ZombieSniffer.png)
可以定位僵尸对象,并且打印出具体堆栈,并模拟系统行为调用 `abort` 。对监控原理和工具实现感兴趣的可以查看这里[带你打造一套 APM 监控系统-内存监控之野指针/内存泄漏监控](https://github.com/FantasticLBP/knowledge-kit/blob/master/Chapter1%20-%20iOS/1.74.md#zombieSniffer)