NSString的内存分配及管理

本文详细介绍了在Objective-C中初始化NSString的三种方法:直接赋值、类函数初始化和实例方法初始化,并探讨了不同初始化方式下字符串的内存分配及引用计数情况。

本文参考了这篇文章,主要做了补充说明:http://www.cnblogs.com/hellocby/archive/2012/08/23/2652201.html

生成一个NSString类型的字符串有三种方法:

方法1.直接赋值:    NSString *testStr1 = @"a";

方法2.类函数初始化生成:     

    NSString *testStr2 = [NSString stringWithString:@"b"];

    NSString *testStr3 = [NSString stringWithFormat:@"c"];

 方法3.实例方法初始化生成: 

    NSString *testStr4 = [[NSString alloc] initWithString:@"d"];

    NSString *testStr5 = [[NSString alloc] initWithFormat:@"e"];

首先查看它们的地址和引用计数:

2012-10-11 17:35:25.601 StringDemo[8514:11303] test1Address:0x4698

2012-10-11 17:35:25.601 StringDemo[8514:11303] test2Address:0x46a8

2012-10-11 17:35:25.602 StringDemo[8514:11303] test3Address:0x746c820

2012-10-11 17:35:25.602 StringDemo[8514:11303] test4Address:0x46c8

2012-10-11 17:35:25.603 StringDemo[8514:11303] test5Address:0x7455990

 

2012-10-11 17:35:25.585 StringDemo[8514:11303] test1:4294967295

2012-10-11 17:35:25.586 StringDemo[8514:11303] test2:4294967295

2012-10-11 17:35:25.596 StringDemo[8514:11303] test3:1

2012-10-11 17:35:25.600 StringDemo[8514:11303] test4:4294967295

2012-10-11 17:35:25.600 StringDemo[8514:11303] test5:1

 

从上可以看出,test1,test2,test4都是在一个内存区域,也就是上文所说的常量内存区。test3,test5在一个内存区,也就是堆区。

这里就有一个疑问:[NSString alloc] initWithString:@"d"这种方式初始化的字符串,也就是test4.应该是位于堆区的,但为什么会跑到常量内存区来呢?据说是因为xcode对这种方式做了处理,还包括[NSString stringWithString:@"b"]这种方式,这两种初始化字符串都等同于@"ddd"了。所以说test2,test4都同等于test1了。

还有,对于NSString *testStr3 = [NSString stringWithFormat:@"c"];这种初始化的字符串,只要一写release语句就会挂掉,但其它的都不会挂掉,test1,test2,test4好理解,因为release本来就不会起作用;但testStr5无论release多少次也不会挂掉,只会在控制台报警告:malloc: *** error for object 0x744d650: double free*** set a breakpoint in malloc_error_break to debug。这个猜测应该是也xcode做了优化吧。

对现在4.4之后的编译器,NSString *testStr2 = [NSString stringWithString:@"b"];这种写法会报警告了:Using 'stringWithString' with a literal is redundant。也就是说这种写法是多余的了,它给的建议是用=@"b"这种方式来代替了。

小结下吧:

对NSString的初始化方法,对于test1,test2,test4这三种的话建议用=@“字符串”来使用,因为本来就是一样的。test3,test5这两种的话,建议用texst3这种,方便点,不用管内存问题,系统自已管理。


### 内存管理机制详解 iOS 的内存管理机制主要分为两种模式:**ARC**(自动引用计数)和**MRC**(手动引用计数)。Objective-C 通过引用计数来管理对象的生命周期,确保内存的合理分配与释放。 在 MRC 模式下,开发者需要手动调用 `retain`、`release` 和 `autorelease` 等方法来管理对象的引用计数。例如: ```objc MyClass *obj = [[MyClass alloc] init]; // retainCount = 1 [obj retain]; // retainCount = 2 [obj release]; // retainCount = 1 [obj release]; // retainCount = 0, 对象被释放 ``` 在 ARC 模式下,编译器会自动插入适当的内存管理代码,开发者无需手动调用这些方法。ARC 会根据对象的使用情况自动管理内存,从而减少内存泄漏和野指针的风险。 ARC 有效时,id 类型和对象类型必须附加所有权修饰符,包括 `__strong`、`__weak`、`__unsafe_unretained` 和 `__autoreleasing`。其中 `__strong` 是默认修饰符,表示强引用,会增加对象的引用计数;而 `__weak` 表示弱引用,不会增加引用计数,并在对象被释放时自动置为 `nil` [^3]。 ### ARC 与 MRC 区别 ARC 和 MRC 的主要区别在于内存管理的自动化程度。MRC 要求开发者手动管理内存,容易出错且维护成本高;而 ARC 则由编译器自动插入内存管理代码,减少了内存泄漏和野指针的可能性。 在 MRC 中,开发者必须显式调用 `retain` 和 `release` 来控制对象的生命周期。而在 ARC 中,这些操作由编译器自动完成。例如,在 ARC 环境下,以下代码会自动处理内存管理: ```objc MyClass *obj = [[MyClass alloc] init]; // 自动 retain obj = nil; // 自动 release ``` 此外,ARC 引入了所有权修饰符,使得内存管理更加精细。`__strong` 表示强引用,会保持对象的存活;而 `__weak` 则用于避免循环引用,常用于代理模式和闭包中 [^3]。 尽管 ARC 简化了内存管理,但某些 Core Foundation 类型(如 `CFStringRef`)仍然需要手动管理内存,因为它们不属于 Objective-C 的 ARC 管理范围 [^1]。 ### 内存泄漏预防方法 内存泄漏是 iOS 开发中常见的问题,通常由循环引用或未释放的对象引起。为了预防内存泄漏,可以采取以下措施: 1. **使用弱引用**:在可能产生循环引用的情况下,使用 `__weak` 修饰符来打破循环。例如,在代理模式中,代理属性应声明为 `weak`: ```objc @property (nonatomic, weak) id<MyDelegate> delegate; ``` 2. **避免强引用循环**:在使用闭包时,避免在闭包内部强引用外部对象。可以通过捕获列表使用 `weakSelf` 来打破循环: ```objc __weak typeof(self) weakSelf = self; dispatch_async(dispatch_get_main_queue(), ^{ __strong typeof(weakSelf) strongSelf = weakSelf; [strongSelf doSomething]; }); ``` 3. **使用 Instruments 工具**:Xcode 提供了 Instruments 工具,可用于检测内存泄漏。通过 Leaks 工具可以识别未释放的对象,并查看其引用路径。 4. **及时释放资源**:对于不再使用的对象,及时将其置为 `nil`,以便 ARC 能够自动释放内存。 5. **注意 Core Foundation 对象管理**:以 `CF` 开头的 Core Foundation 类型(如 `CFStringRef`)需要手动管理内存,使用 `CFRetain` 和 `CFRelease` 进行引用和释放 [^1]。 6. **合理使用 autoreleasepool**:在大量创建临时对象的循环中,使用 `@autoreleasepool` 可以及时释放内存,避免内存峰值过高: ```objc for (int i = 0; i < 1000; i++) { @autoreleasepool { NSString *str = [[NSString alloc] initWithFormat:@"Item %d", i]; // 使用 str } } ``` 通过上述方法,可以有效预防内存泄漏,提升应用的稳定性和性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值