NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString * str = [[NSString alloc] initWithString:@"test"];
[str release];
int i = 999999999;
while(i-- > 0) {}
NSLog(@"%@", str);
[pool drain];
输出:测试
为什么release
无效?
如何立即从内存中删除对象?
Xcode 4.0版iPhone应用程序
<小时/> 的〜解决〜
我知道发布只是“标记”记忆“愿意被释放”,但不能立即释放它
答案 0 :(得分:6)
发布确实有效,但您尝试做的事情有未定义的行为,并且在使用NSString和文字时,您可能也会遇到不同的行为。发生的事情是,虽然您的对象被释放,但该位置的内存可以回收并且没有更改,当它打印时它仍然有效。由于它是一个NSString,因此不一定要发送描述消息,这就是为什么你没有因为尝试发送一个解除分配的对象而得到异常。
This question有一些关于NSString和NSLog的好信息。
答案 1 :(得分:6)
确实有效。您已放弃该对象的所有权,并且当系统确定它不再拥有时,系统将标记为可供系统重用。如果您是该字符串的唯一所有者,那可能会立即发生。如果字符串的创建导致它在内部自动释放,则可能会在稍后的某个时间点发生。或者,正如Dave DeLong指出的那样,系统可能会将其优化为一个永不释放的对象。
在您的情况下,它被优化为一个常量字符串,该字符串将在程序的生命周期中存在。如果您使用的是NSMutableString
而不是NSString
,您会看到可能不会崩溃的时髦行为,但不会打印您所期望的内容。 (有关示例,请参阅this question。)
如果您使用的是NSArray
,那么当您调用release
时 将被取消分配,但您仍然会看到您的NSLog示例正常工作,直到您分配了其他一些宾语。释放只是将内存标记为可重用;它实际上并没有清除它。因此,如果您将数组传递给NSLog,则该内存尚未更改,因此仍可正确打印。
然而,所有这一切的关键点是要认识到调用release
不一定会导致对象被释放。它可能因任何原因而继续存在。但是一旦你打电话给release
,你就放弃了对象的所有权。如果你在那之后继续使用它,系统可以自由地做各种奇怪的事情,如图所示。
答案 2 :(得分:4)
当你这样做时:
NSString * str = [[NSString alloc] initWithString:@"test"];
这将优化为:
NSString * str = @"test";
你不能release
一个常量字符串,因为它被硬编码到应用程序二进制文件中。
证明:
NSString *s = [NSString alloc];
NSLog(@"%p", s);
s = [s initWithString:@"foo"];
NSLog(@"%p", s);
s = @"foo";
NSLog(@"%p", s);
日志:
2011-04-12 10:17:45.591 EmptyFoundation[6679:a0f] 0x100116370
2011-04-12 10:17:45.599 EmptyFoundation[6679:a0f] 0x100009270
2011-04-12 10:17:45.604 EmptyFoundation[6679:a0f] 0x100009270
您可以看到+alloc
的结果与-initWithString:
的结果不同,-initWithString:
的结果等同于常量字符串。基本上,-initWithString:
说“啊哈,我将成为一个不可变的字符串,我将被赋予一个不可变的字符串!我可以采取一个捷径,摧毁自己,并返回参数,一切都将仍然工作相同“
答案 3 :(得分:1)
您在NSLog()中使用了错误的指针。在这种情况下,你碰巧变得幸运,但你应该期望这样的代码在其他方面崩溃或失败。
答案 4 :(得分:0)
无需删除内存块,这将耗尽不需要的周期。 当分配新对象占用该内存块时,将覆盖内存。