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(@"\r str: %@,\r weakStr: %@,\r strongStr: %@,\r copyStr: %@,\r mutableCopyStr: %@", str, weakStr, strongStr, copyStr, mutableCopyStr);
    NSLog(@"\r str2: %@,\r weakStr2: %@,\r strongStr: %@,\r copyStr2: %@,\r mutableCopyStr2: %@", str2, weakStr2, strongStr2, copyStr2, mutableCopyStr2);
    NSLog(@"\r mutableStr: %@,\r weakMutableStr: %@\r strongMutableStr: %@,\r copyMutableStr: %@,\r mutableCopyMutableStr: %@", mutableStr, weakMutableStr, strongMutableStr, copyMutableStr, mutableCopyMutableStr);
#else
    NSLog(@"\r str: %@,\r retainStr: %@,\r copyStr: %@,\r mutableCopyStr: %@", str, retainStr, copyStr, mutableCopyStr);
    NSLog(@"\r str2: %@,\r retainStr2: %@,\r copyStr2: %@,\r mutableCopyStr2: %@", str2, retainStr2, copyStr2, mutableCopyStr2);
    NSLog(@"\r mutableStr: %@,\r retainMutableStr: %@,\r copyMutableStr: %@,\r 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均会创建新的对象。

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

三、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保留本文的一切权利

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

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

  

iOS: ARC & MRC下string内存管理策略探究,布布扣,bubuko.com

时间: 2024-10-14 09:14:11

iOS: ARC & MRC下string内存管理策略探究的相关文章

iOS内存管理策略和实践

来源:http://www.baidu.com/link?url=irojqCBbZKsY7b0L2EBPkuEkfJ9MQvUf8kuNWQUXkBLk5b22Jl5rjozKaJS3n78jCnSsUZjVQvFIW1IKcJMlR2fGj9eiy-gCY7ulTRyEuAi 关于iOS内存管理 应用程序内存管理是:程序运行时,开辟的内存空间.使用它,释放它的过程,写的好的程序尽可能少使用内存.在Objective-C中,内存管理被看做是:在很多数据.代码下,分配 转自hherima的博客

ARC下的内存管理

1.ARC下单对象内存管理 局部变量释放对象随之被释放 int main(int argc, const char * argv[]) { @autoreleasepool { Person *p = [[Person alloc] init]; } // 执行到这一行局部变量p释放 // 由于没有强指针指向对象, 所以对象也释放 return 0; } 清空指针对象随之被释放 int main(int argc, const char * argv[]) { @autoreleasepool

Redis 数据结构与内存管理策略(下)

Redis 数据结构与内存管理策略(下) Redis 数据类型特点与使用场景 String.List.Hash.Set.Zset 案例:沪江团购系统大促 hot-top 接口 cache 设计 Redis 内存数据结构与编码 OBJECT encoding key.DEBUG OBJECT key 简单动态字符串(simple dynamic string) 链表(linked list) 字典(dict) 跳表(skip list) 整数集合(int set) 压缩表(zip list) Re

iOS经典面试题总结--内存管理

iOS经典面试题总结--内存管理 内存管理 1.什么是ARC? ARC是automatic reference counting自动引用计数,在程序编译时自动加入retain/release.在对象被创建时retain count+1,在对象被release时count-1,当count=0时,销毁对象.程序中加入autoreleasepool对象会由系统自动加上autorelease方法,如果该对象引用计数为0,则销毁.那么ARC是为了解决MRC手动管理内存存在的一些而诞生的. MRC下内存管

内存管理策略

内存管理策略 在引用计数的环境下管理内存使用的基本模型是,通过在NSObject协议定义的方法和提供标准命名的方法.NSObject类也定义了一个方法"dealloc",当一个对象被释放时此函数被调用.本文介绍了您需要知道的,如何正确的管理内存在一个Cocoa程序,并提供了一些正确的使用实例. 基本内存管理规则 内存管理模型是基于对象所有权的.任何一个对象可能会有一个或者多个所有者.只要一个对象有至少一个所有者,那么它需要继续退出.当一个对象没有所有者时,系统会自动销毁它. 为了确保你

常见Key-Value存储系统的内存管理策略解析

Key-Value存储作为NoSQL存储的一种常见方式,提供了比SQL数据库更好的可扩展性和读写性能.比如当前开源最热门的Memcached和Redis:淘宝的Tair.腾讯的Cmem.Amazon的Dynamo等等,无论是做缓存还是持久存储,均使用内存作为主要存储介质,故内存管理策略就显得尤为重要了,是影响性能的重要因素. 这里从源代码层面对Memcached.Redis和UDC(腾讯以前用的一套KV持久化存储系统)的内存管理策略进行分析,3者的内存管理策略各不相同,其他KV系统也和这3种方法

ARC模式下的内存泄露问题

ARC模式下的内存泄露问题 iOS提供的ARC 功能很大程度上简化了编程,让内存管理变得越来越简单,但是ARC并不是说不会发生内存泄露,使用不当照样会发生. 以下列举两种内存泄露情况: 死循环造成的内存泄露 若一个ViewController中存在无限循环,就会导致即使ViewController所对应的View消失掉了,ViewController对象也不能够被释放. 此问题通常发生在animation处理中: eg: CATransition *transition = [CATransit

cocos2d-x 源码分析 : Ref (CCObject) 源码分析 cocos2d-x内存管理策略

源码版本来自3.x,转载请注明 cocos2d-x 源码分析总目录: http://blog.csdn.net/u011225840/article/details/31743129 1.Ref,AutoreleasePool,PoolManager Ref中包含了一个叫referenceCount的引用计数,当一个Ref类的变量被new的时候,其referenceCount的引用计数被置为1. 其中有三个重要的操作,retain,release,autorelease,下面源码分析时会详细说明

Rs2008内存管理策略

Rs2008 在内存管理方面已经有了很大的改变.主要增加了文件缓存,允许把内存数据卸载到文件缓存中.而Rs2005 都是把数据放到内存中.对于大数据量的报表而言,很容易出现OutOfMemory 错误. 在实际应用中,发现Rs2008 也经常出现 OutOfMemory 错误.主要有以下几个原因: 1 物理内存过低. 机器只有2G内存,特别是64位的机器. 2 同一台服务器同时承担两种角色: 数据库服务器,报表服务器.但没有限定数据库服务器的占用的最大内存. 由于数据库通常会采用贪婪的内存策略获