Dav*_*ong 9 memory-management objective-c autorelease
我试图将一个bug缩小到最小可重复的情况并发现一些奇怪的东西.
考虑以下代码:
static NSString *staticString = nil;
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
if (staticString == nil) {
staticString = [[NSArray arrayWithObjects:@"1", @"2", @"3", nil] componentsJoinedByString:@","];
}
[pool drain];
NSLog(@"static: %@", staticString);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我期待这段代码崩溃.相反,它记录:
2011-01-18 14:41:06.311 EmptyFoundation[61419:a0f] static: static:
Run Code Online (Sandbox Code Playgroud)
但是,如果我NSLog()改为:
NSLog(@"static: %s", [staticString UTF8String]);
Run Code Online (Sandbox Code Playgroud)
然后,它不会崩溃.
编辑更多信息:
排水后:
NSLog(@"static: %@", staticString); //this logs "static: static: "
NSLog(@"static: %@", [staticString description]); //this crashes
Run Code Online (Sandbox Code Playgroud)
所以显然在字符串上调用一个方法就足以让它崩溃了.在这种情况下,为什么不直接记录字符串导致它崩溃?不NSLog()应该调用-description方法?
第二个"静态"来自何处?为什么这不会崩溃?
结果:
Kevin Ballard和Graham Lee都是正确的.格雷厄姆在意识到正确的NSLog()是不调用-description(因为我是错误的假设),和凯文几乎是绝对正确的,这是复制一个格式字符串和一个奇怪的堆栈相关的问题va_list各地.
NSLogging并且NSString不会调用-description.格雷厄姆优雅地展示了这一点,如果你追踪进行日志记录的核心基金会来源,你会发现情况就是如此.源自内部的任何回溯都NSLog表明它调用NSLogv=> _CFLogvEx=> _CFStringCreateWithFormatAndArgumentsAux=> _CFStringAppendFormatAndArgumentsAux. _CFStringAppendFormatAndArgumentsAux()(第5365行)是所有魔法发生的地方.您可以看到它是手动查找所有%替换.如果替换的类型是a CFFormatObjectType,描述函数是非零的,并且替换尚未被另一种类型处理,它最终只会调用描述复制函数.由于我们已经证明描述没有被复制,因此可以合理地假设NSString早期处理(在这种情况下它可能会进行原始字节复制),这使我们相信......NSString.所以,它不会崩溃.奇怪的.但是,如果我们将静态变量的类型更改为其他内容(如a)NSArray,则会-description调用该方法,并且程序会按预期崩溃.多么真实和完全奇怪.关于这个行为的根本原因,凯文是最正确的要点,并赞扬格雷厄姆纠正我的谬误.我希望我能接受两个答案......
我对你所看到的最好的猜测是NSLog()复制格式字符串(可能是一个可变副本),然后解析参数.由于你已经dealloc'd staticString,所以恰好将格式字符串的副本放在同一个位置.这会导致您看到"static: static: "您描述的输出.当然,这种行为是未定义的 - 不能保证它总是会使用相同的内存位置.
另一方面,您NSLog(@"static: %s", [staticString UTF8String])正在staticString格式字符串复制发生之前访问,这意味着它正在访问垃圾内存.
小智 8
您对实例NSLog()调用的假设是错误的.我刚刚添加了这个类别:-descriptionNSString
@implementation NSString (GLDescription)
- (NSString *)description {
NSLog(@"-description called on %@", self);
return self;
}
@end
Run Code Online (Sandbox Code Playgroud)
它不会导致堆栈溢出,因为它不会被递归调用.不仅如此,如果我将该类别插入到您问题的代码中,我会发现此输出:
2011-01-18 23:04:11.653 LogString[3769:a0f] -description called on 1
2011-01-18 23:04:11.656 LogString[3769:a0f] -description called on 2
2011-01-18 23:04:11.657 LogString[3769:a0f] -description called on 3
2011-01-18 23:04:11.658 LogString[3769:a0f] static: static:
Run Code Online (Sandbox Code Playgroud)
因此,我们得出结论,NSLog()不叫-description上NSString在其ARGS遇到.当您错误地访问已释放的staticString变量时,为什么两次获取静态字符串可能是堆栈中数据的怪癖.
| 归档时间: |
|
| 查看次数: |
1230 次 |
| 最近记录: |