[iOS]关于内存管理的一些总结

前言

内存管理作为iOS最基础的存在,其重要性不言而喻.平时因为忙业务,遇到一些内存相关的问题,然后才有了这篇小结.

AutoreleasePool

几个Tips:

  1. AutoreleasePool在非手动添加的情况下,是在当前runloop完了之后才会释放对象.
  2. 子线程的runloop默认不开启,那系统会自动添加AutoreleasePool吗?答案是肯定的,从这篇文章可以看到原理,通过调用autoreleaseNoPage方法来进行处理.
  3. 以new,alloc初始化的对象编译器会自动为这个对象添加release语句,而类似于id object1 = object2;这种会自动包裹一个AutoreleasePool.
  4. 当我们在使用enumerateObjectsUsingBlock这个方法进行遍历的时候,内部也会自动包裹一个AutoreleasePool,所以不需要手动添加.

循环引用

这里先给一段代码,两个类TestA,TestB,重写了dealloc方法,便于观察释放与否.TestA内有一个TestB类型的属性b,TestB内有一个TestA类型的属性a.

    TestA *ta = [[TestA alloc] init];
    TestB *tb = [[TestB alloc] init];
    ta.b = tb;//A的b属性指向tb
    tb.a = ta;//B的a属性是想ta

这里毫无疑问会有循环引用,于是自然会想到:

ta = nil;
或者
tb = nil;

但是结果运行之后依然没有打印dealloc方法.这是为什么呢?
用Leaks分析循环引用关系:

[iOS]关于内存管理的一些总结_第1张图片

我们发现循环的链条关键点在于 _a_b,我们应该打断这两条蓝线其中的一条.

ta.b = nil;
或则
tb.a = nil;

然后运行发现对象确实被销毁了.
这里令我百思不得其解的是:ta或者tb都是这个链条的一部分,为什么对他们置为nil不产生效果呢?我尝试这样写:

    ta.b = tb;//A的b属性指向tb
    ta = nil;
    tb.a = ta;//B的a属性是想ta

发现这样也是可以销毁的,道理很简单:循环引用还没建立就销毁一个对象.这样感觉也没有意义.之后和小伙伴们讨论了一下,得出如下值得验证的结论:

当我设置ta = nil 或者 tb = nil的时候,其实并没有打断这个循环引用的链条,他们的循环引用已经形成了,ta持有b,b的指针指向tb,如果我们要打破这个循环引用首先应该切断指向ta或者tb的指针,也就是ta.b或者tb.a,是这两个指针直接指向的两个对象,切断这种指向才是必要之举.

其实还有些许迷惑,希望有人能给出一些指点.

参考资料
http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
https://www.jianshu.com/p/f87f40592023

你可能感兴趣的:([iOS]关于内存管理的一些总结)