美文网首页
内存管理之函数参数的__strong、引用计数问题

内存管理之函数参数的__strong、引用计数问题

作者: 9a957efaf40a | 来源:发表于2018-08-10 11:05 被阅读70次

以下的测试均基于ARC

1.__strong修饰符

在如下函数中:

- (void)xx {
    Son *son = [[Son alloc] init];
    Son *s1 = son;
    NSLog(@"%ld",(long)CFGetRetainCount((__bridge CFTypeRef)(son)));
}

son的引用计数是多少?

2018-08-10 09:48:12.275410 内存管理[1597:362731] 2

这是因为s1默认为__strong修饰,则编译器自动添加retain函数,底层调用objc_retain函数,增加了对象的引用计数。相关的汇编代码如下:

4DB6D79F-1721-4D54-92D1-A5EB298C2EA5.png

第一个objc_msgSendalloc,第二个objc_msgSendinit,下面依次是objc_retain和打印时调用的函数CFGetRetainCount

2.__weak修饰符

如果添加了__weak会发生什么?

- (void)xx {
    Son *son = [[Son alloc] init];
    __weak Son *s1 = son;
    NSLog(@"%ld",(long)CFGetRetainCount((__bridge CFTypeRef)(son)));
}

结果为:

2018-08-10 09:58:20.115245 内存管理[1606:364519] 1

相关汇编如下:


B0F7DFC2-EAC4-410C-878B-2725A6E927BC.png

不再调用objc_retain,取而代之的是objc_initWeak

3.参数的引用计数

如下函数中:

void test(Son *s){
    NSLog(@"%ld",(long)CFGetRetainCount((__bridge CFTypeRef)(s)));
}
int main(int argc, char * argv[]) {
    Son *s = [[Son alloc] init];
    test(s);
}

test(Son *s)函数中,s指针不像我们在示例1和示例2中定义的那样,没有明确的__strong__weak修饰符,甚至都无法知道s指针是如何定义的。那么,s会对传递的对象增加引用计数吗?

结果如下:

2018-08-10 10:05:07.315869 内存管理[1611:365666] 2

显然,作为参数传递的对象,进入函数后,会增加一次引用计数。

那么这一切是怎么做的?

7CCF660C-EA78-4967-8219-CC900AF65D20.png
  • 1~3行为拉伸栈空间和保护寄存器,我们不讨论。
  • 4行将sp中的值加上0x20,然后赋值给x29sp中的值为0x000000016fd6fa10。则x290x000000016fd6fa30
  • 5行将x29的值减去0x8,然后赋值给x8。则x8的值为0x000000016fd6fa28
  • 6行将x9中的值置为0x0
  • 7行,取x29的值减去0x8后的值作为地址,将x9中的值0x0写入到该地址的内存中。(结合第5行,也就是说,如果x8的值做为地址,该地址的值的前8个字节(一个指针的宽度)为空。这个转化很重要!!!)
  • 8行,取sp的值加上0x10后的值作为地址,将x0的值写入到该地址的内存空间中。x0寄存器保存函数调用时的第一个参数,那么在这里,它的值就是参数s
    705FB3F3-6412-49DE-8706-1AF8BCD8A872.png
  • 9行,将x8的值给x0。此时x0的值为0x000000016fd6fa28
  • 10行,将sp的值加上0x10后的值作为地址,从该地址的内存空间中取出值赋给x1。此时x1的值为s指针,指向Son对象。
  • 11行,调用objc_storeStrong函数。
void objc_storeStrong(id *location, id obj)
{
    id prev = *location;
    if (obj == prev) {
        return;
    }
    objc_retain(obj);
    *location = obj;
    objc_release(prev);
}

可以看到,该函数需要两个参数。
第一个参数为二级指针。而此时x00x000000016fd6fa28,上面我们说过,如果这个值作为地址,该地址的值的前8个字节(一个指针的宽度)是空。那么也就是说,该函数中id prev为空。
第二个参数为OC对象。此时x1的值为指针s
可以看到,obj != prev,因此执行objc_retain(obj)Son对象的引用计数加1,为2。
此时0x000000016fd6fa28作为地址,值的前8个字节不再是空,而是指向Son对象的指针。

汇编中间打印部分我们不讨论,现在,跳到第20行。

  • 20行,x8置空。
  • 21行,取x29的值减去0x8后的值,赋给x9x90x000000016fd6fa28。此时该值作为地址,该地址的值的前8个字节,在经过第11行的函数objc_storeStrong后,已经不再是空,而是一个指针,指向Son对象。
  • 22~23行,x00x000000016fd6fa28x10x0
  • 24行,调用objc_storeStrong函数。

此时第一个参数为二级指针,取值为id prev,prev为指向Son对象的指针。
第二个参数obj为空。
可以看到,obj != prev,因此执行objc_retain(nil),然后0x000000016fd6fa28作为地址,该地址的值的前8个字节置为空,最后objc_release(prev),即Son对象的引用计数减1。

结论 : OC对象参数在进入函数时,会增加引用计数,在函数结束时,会减少引用计数。

相关文章

  • 内存管理之函数参数的__strong、引用计数问题

    以下的测试均基于ARC 1.__strong修饰符 在如下函数中: son的引用计数是多少? 这是因为s1默认为_...

  • ios循环引用

    首先,研究ios循环引用,离不开怎么使用strong和weak类型的引用和mrc下内存管理和arc下的内存管理。a...

  • Swift 内存管理

    Swift 中使用自动引用计数(ARC)机制来追踪和管理内存 强引用strong和无主引用unowned 通过阅读...

  • 基础总结

    一、内存管理 1、循环引用 四个关键字 strong assign weak copy 对比 引用计数器问题 al...

  • iOS strong和weak的内存管理情况

    对于strong和weak的内存管理情况一直没有弄太明白,只是简单的理解为强引用和弱引用,弱引用可以解决循环引用问...

  • 经典问题

    arc有什么好处 引用计数方式的内存管理方式没有变,只是自动地帮我们去处理引用计数 strong变量在超出变量作用...

  • Q:Java有几种引用类型?

    Java有几种引用类型 引自 java 知识 之 内存管理 Java 中的内存管理包括内存分配和内存回收,这些都是...

  • RxSwift学习之十七 (内存管理,循环引用问题

    @[TOC](RxSwift学习之十七 (内存管理,循环引用问题)) 1. Rxswift内存管理简介 Rxswi...

  • copy-strong

    Copy,Strong的区别需要了解点内存管理的知识,Strong是ARC下引入的修饰,相当于手动管理内存(MRC...

  • 第10章 内存管理和文件操作

    1 内存管理 1.1 内存管理基础 标准内存管理函数堆管理函数虚拟内存管理函数内存映射文件函数 GlobalMem...

网友评论

      本文标题:内存管理之函数参数的__strong、引用计数问题

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