zoukankan      html  css  js  c++  java
  • iOS: ARC & MRC下string内存管理策略探究

    ARC & MRC下string内存管理策略探究 

      

      前两天跟同事争论一个关于NSString执行copy操作以后是否会发生变化,两个人整了半天,最后写代码验证了一下,发现原来NSString操作没我们想的那么简单,下面就让我们一起看看NSString和NSMutableString在MRC下执行retain,copy,mutableCopy,以及ARC下不同的修饰__weak, __strong修饰赋值究竟发生了什么。

    一、验证代码如下:

    - (void)testStringAddress
    {
        int a = 0;
        int b = 0;
        
        static int c = 0;
        
        NSString *str = @"Hello World";
        
    #if __has_feature(objc_arc)
        __weak   NSString *weakStr = str;
        __strong NSString *strongStr = str;
    #else
        NSString *retainStr = [str retain];
    #endif
        
        NSString *copyStr = [str copy];
        NSMutableString *mutableCopyStr = [str mutableCopy];
        
        // 验证mutableCopy出来的是否是mutableString,如果不是执行此行会Crash
        [mutableCopyStr appendFormat:@".."];
        str = @"i'm changed";
        
        NSString *str2 = [NSString stringWithFormat:@"Hello world"];
        
    #if __has_feature(objc_arc)
        __weak   NSString *weakStr2 = str2;
        __strong NSString *strongStr2 = str2;
    #else
        NSString *retainStr2 = [str2 retain];
    #endif
        
        NSString *copyStr2 = [str2 copy];
        NSString *copy2Str2 = [str2 copy];
        NSString *mutableCopyStr2 = [str2 mutableCopy];
        NSString *mutableCopy2Str2 = [str mutableCopy];
        str2 = [[NSString alloc] initWithFormat:@"changed"];
        
        NSMutableString *mutableStr = [NSMutableString stringWithString:@"hello world"];
        
    #if __has_feature(objc_arc)
        __weak   NSMutableString *weakMutableStr = mutableStr;
        __strong NSMutableString *strongMutableStr = mutableStr;
    #else
        NSMutableString *retainMutableStr = [mutableStr retain];
    #endif
        
        NSMutableString *copyMutableStr = [mutableStr copy];
        NSMutableString *copy2MutableStr = [mutableStr copy];
        NSString *mutableCopyMutableStr = [mutableStr mutableCopy];
        NSString *mutableCopy2MutableStr = [mutableStr mutableCopy];
        [mutableStr appendFormat:@" apped something"];
    
    #if __has_feature(objc_arc)
        NSLog(@"
     str: %@,
     weakStr: %@,
     strongStr: %@,
     copyStr: %@,
     mutableCopyStr: %@", str, weakStr, strongStr, copyStr, mutableCopyStr);
        NSLog(@"
     str2: %@,
     weakStr2: %@,
     strongStr: %@,
     copyStr2: %@,
     mutableCopyStr2: %@", str2, weakStr2, strongStr2, copyStr2, mutableCopyStr2);
        NSLog(@"
     mutableStr: %@,
     weakMutableStr: %@
     strongMutableStr: %@,
     copyMutableStr: %@,
     mutableCopyMutableStr: %@", mutableStr, weakMutableStr, strongMutableStr, copyMutableStr, mutableCopyMutableStr);
    #else 
        NSLog(@"
     str: %@,
     retainStr: %@,
     copyStr: %@,
     mutableCopyStr: %@", str, retainStr, copyStr, mutableCopyStr);
        NSLog(@"
     str2: %@,
     retainStr2: %@,
     copyStr2: %@,
     mutableCopyStr2: %@", str2, retainStr2, copyStr2, mutableCopyStr2);
        NSLog(@"
     mutableStr: %@,
     retainMutableStr: %@,
     copyMutableStr: %@,
     mutableCopyMutableStr: %@", mutableStr, retainMutableStr, copyMutableStr, mutableCopyMutableStr);
    #endif
    }
    testStringAddress

      代码中最开始定义了两个int型的变量,主要是为了打印出当前函数的栈地址,顺便验证了一下内存中栈是从高地址向低地址生长的。使用预编译宏#if __has_feature(objc_arc)来检测当前是否是ARC环境,并根据不同环境写了不同的测试代码。

      通过在testStringAddress最后添加断点,在lldb命令行下通过“p”命令输出变量对应的地址,例如:查看str指向的内存地址和内容,输入"p str"即可。

      调试环境xCode6 beta4,iOS8 SDK。

    二、MRC下执行情况

      执行结果如下图所示:

      解释一下上图的内容:

      1、第一部分

      “p &str”表示打印str这个变量本身的地址,“p str”表示打印str指向的内容的地址。如上图所示,"p &str"打印出来的结果是0xbff0aff8,局部变量b的地址为0xbff0affc,我们可以看出这两者的内存地址是相连,因为他们都是函数体内部局部变量。而“p str”打印出来的结果是0x000a7048,说明str指向的内容的存储区域和函数局部变量不在一起。

      2、第二部分

      c是我在函数中定义的一个static变量,“p &c”打印出来的地址为0x000a778c,观察可知变量c和函数变量也不在一起。static变量在程序运行过程中只会有一个,位于程序的静态变量区。

      3、第三部分

      str的定义为“NSString *str = @"Hello World";”,通过调试发现str指向的内容为0x000a7048,且此时对str执行的retain和copy操作得到的结果地址均为0x000a7028。而执行mutableCopy后得到的NSString的地址为0x7974a110,和str以及retain,copy操作得到的地址不在一起。

      总结:形如@“Hello World”形式的变量在程序的常量区,而NSString在针对常量区的对象首次执行retain和copy时创建新对象,之后执行同类操作则发挥之前创建的对象,mutableCopy操作则在其他地方创建了一个对象,并使用str完成了初始化操作。

      4、第四部分

      str2定义为“NSString *str2 = [NSString stringWithFormat:@"Hello world"];”,打印结果发现str2指向的内容的地址为0x79749000执行retain操作得到的string的指向内容的地址为0x7974a5c0,copy操作得到的地址也是0x7974a5c0,测试发现之后再对str2执行copy操作均会得到相同的地址。这块儿貌似跟我们平时常念的“retain增加引用技术,copy创建新的对象”的观念不符。对str2执行mutableCopy得到的地址为0x7974a380,重新创建了一个对象,符合我们的预期。

      总结:使用stringWithFormat方式创建的NSString对象默认在堆上,对这一类对象首次执行retain或copy操作时会创建一份拷贝,后续所有的retain和copy均会指向之前创建的同一个拷贝,无论何时执行mutableCopy操作均会创建新的对象。

      5、第五部分

      mutableStr的定义为“[NSMutableString stringWithString:@"hello world"];”,打印结果发现对mutableStr执行retain操作得到对象的地址和mutableStr相同,执行copy操作会创建新的对象,执行mutableCopy操作也会创建新的对象。

      总结:使用stringWithString方式创建的NSMutableString对象默认在堆上,对NSMutableString执行retain时不会创建新对象,执行copy和mutableCopy均会创建新的对象。

      观察以上对象地址,大致可以分为四个区间0x000a70xx0x000a78xx0x7974xxxx0xbff5xxxx,其实它们分别依次代表四个不同的内存段常量区,静态变量区,堆区,栈区。

    三、ARC下执行情况

      执行结果如下图:

      分析方法和第一部分一样,这里就不重复了。

      总结:

      1、针对常量区的NSString对象,执行weak,strong赋值活着copy操作只会生成一份拷贝,每次执行mutableCopy时均会创建新的对象。

      2、针对堆上的NSString对象执行weak,strong,copy操作时只会创建一份拷贝,后续所有操作均得到相同的对象,每次执行mutableCopy时均会创建新的对象。

      3、针对NSMutableString对象首次执行weak,strong操作只会创建一份拷贝,后续所有操作均得到相同对象,每次执行copy和mutableCopy操作均会创建新的对象。

    四、总结

      综上ARC和MRC下NSString,NSMutableString执行retain,copy,mutableCopy,weak,strong操作时内存情况见下表格:

    注:smileEvday保留本文的一切权利

      转载请著名出处,有什么问题欢迎留言

      如果觉得本文帮到了你,请推荐给身边的朋友

      

  • 相关阅读:
    获取样式方法
    滚动条--滚动文字
    关于一些英文博客内容
    Don't performan heavy tasks in the MoBu Real-time engine thread, even if it worked before
    Autodesk 2014 M&E Devday is coming
    所有学生和老师的福音,欧特克将在全球免费开放软件给学生老师使用
    Autodesk 年度 AU 大会将在拉斯维加斯举行
    今天折腾了下NodeJs的调试
    如何解决 XMLHttpRequest 跨域请求的问题
    欧特克收购 ShotGun 产品
  • 原文地址:https://www.cnblogs.com/smileEvday/p/stringMemory.html
Copyright © 2011-2022 走看看