美文网首页
内存循环引用算法

内存循环引用算法

作者: 码农苍耳 | 来源:发表于2017-10-07 21:27 被阅读40次

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

开始

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

  1. 自身属性,被定义为strong类型的变量,都会产生一次强引用。
  2. associate object,被定义为retain类型的也会被强引用。
  3. block,在被闭包捕获的时候,strong类型对象也会被强引用。
  4. 特殊对象,比如NSTimertarget,集合类型的addObject

associate object

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

property

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

block

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

其他

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

算法

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

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

// 堆栈用于保存所遍历过的路径
NSMutableArray<FBNodeEnumerator *> *stack = [NSMutableArray new];
// 集合用于保存该路径上的所有对象,用于判断是否有对象相等,也就是循环引用了。
NSMutableSet<FBNodeEnumerator *> *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我们就无法判断子元素的引用情况。还有一些虽然形成了循环引用,但在整个流程的结尾,是必定会解除的,会形成误判。

相关文章

  • 内存循环引用算法

    平时我们最容易犯的一个错误就是循环引用,而且难以察觉,而FBRetainCycleDetector则是专门在运行期...

  • iOS 内存管理、查找循环引用

    内存管理 1、ARC 下的内存管理 循环引用 如图,就是循环引用的情况,A、B 互相引用无法释放。 造成循环引用的...

  • Java基础 (14) 垃圾回收

    1)GC算法(各种算法的优缺点以及应用场景)2)内存对象的循环引用及避免3)内存回收机制、GC回收策略、GC原理时...

  • iOS循环引用

    什么是循环引用? 循环引用:是指多个对象相互引用,导致内存无法释放,从而导致内存泄露。 循环引用的四种情况? 父类...

  • Swift--内存管理

    Swift内存管理概述 强引用循环 打破强引用循环 闭包中的强引用循环 Swift内存管理概述 Swift中的AR...

  • IOS循环引用、内存泄漏、野指针

    一、循环引用和内存泄漏 1、block循环引用 分析:因为WGBlockTestViewController强引用...

  • 垃圾收集器

    判断对象存活的方法: 引用计数算法java虚拟机没有使用引用计数算法管理内存的主要原因是它很难解决对象之间的循环引...

  • iOS内存优化

    引起内存泄漏的原因 引起内存泄漏的原因主要有三类,如下 循环引用 强引用 非OC对象 1、循环引用。最简单的循环引...

  • 强软弱虚(关键词: ThreadLocal,堆外内存)

    前言 引用的作用就是在GC的时候用作判断,一般采用的根可达算法(引用计数法会有循环引用的问题,所以我们不用) 内存...

  • 内存管理、自动释放池与循环引用

    内存布局 内存管理方案 MRC(手动引用计数)和ARC(自动引用计数) 循环引用 一、内存布局 栈(stack):...

网友评论

      本文标题:内存循环引用算法

      本文链接:https://www.haomeiwen.com/subject/rgjsyxtx.html