c语言 循环引用,内存循环引用算法

本文解析了ARC环境下的强引用机制,重点介绍了FBRetainCycleDetector如何通过hook技术追踪关联对象和属性,利用堆栈算法检测循环引用。讨论了算法原理和局限性,如对CFArray和NSHashMap的处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平时我们最容易犯的一个错误就是循环引用,而且难以察觉,而FBRetainCycleDetector则是专门在运行期来检查循环引用,那我们来看看他是怎么做到的。

开始

首先,我们来看看在arc环境下,什么时候会发生强引用。

自身属性,被定义为strong类型的变量,都会产生一次强引用。

associate object,被定义为retain类型的也会被强引用。

block,在被闭包捕获的时候,strong类型对象也会被强引用。

特殊对象,比如NSTimer的target,集合类型的addObject。

associate object

如何记录associate object的持有情况呢?这里要说一下C语言的hook,也就是在链接的时候替换掉objc_setAssociatedObject方法,然后记录源对象和持有对象。关于hook可以参考fishhook这个库。

property

objc的对象会有自身的布局记录(layout),取出每个类中的Ivar的属性,就可以知道哪些属性是强引用的,也就可以知道每个对象所持有的对象了。

block

和property一样,每个block也是有对应的layout的。

其他

其他一些特殊情况,则需要特殊考虑,细节这里就不说明了。

算法

首先,我们将每个需要检测的对象视作一颗颗树,叶子是每个强引用的对象。

作者使用了堆栈来替换递归实现路径点的查找,基本原理是:

// 堆栈用于保存所遍历过的路径

NSMutableArray *stack = [NSMutableArray new];

// 集合用于保存该路径上的所有对象,用于判断是否有对象相等,也就是循环引用了。

NSMutableSet *objectsOnPath = [NSMutableSet new];

// ...

while ([stack count] > 0) {

// ...

if ([objectsOnPath containsObject:firstAdjacent]) {

// 发现循环引用并记录 ...

} else {

// ...

shouldPushToStack = YES;

}

[objectsOnPath addObject:top];

// 如果没有发现循环引用,则查找其子节点,并push进堆栈

if (shouldPushToStack) {

if ([stack count] < stackDepth) {

[stack addObject:firstAdjacent];

}

}

else {

// 如果已经没有子节点了,就退出堆栈,开始判定父节点的下一个节点

[stack removeLastObject];

[objectsOnPath removeObject:top];

}

}

算法其实很简单,源码也就100行以内。

最后

这种方式给予我们一种能够在运行时检查循环引用的方法,但是这并不代表完全正确,比如CFArray,NSHashMap我们就无法判断子元素的引用情况。还有一些虽然形成了循环引用,但在整个流程的结尾,是必定会解除的,会形成误判。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值