最近我注意到 Xcode 中 Objective C 内存管理的奇怪行为。 代码如下:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString *firstString = [[NSString alloc] initWithString: @"Hello"];
NSString *secondString = firstString;
[firstString release];
NSLog(@"%@", secondString);
}
return 0;
}
我认为,释放 firstString 后 secondString 指向 nil 并且 NSLog 应该会产生错误。 但是此代码不会产生任何错误并成功打印“Hello”字符串。 我用这样的命令手动编译和运行代码,也没有发现任何错误:
% clang -framework Foundation -fno-objc-arc main.m && ./a.out
我尝试使用在线 Objective-C 编译器 (GCC) (http://rextester.com/l/objectivec_online_compiler) 编译此代码,但出现错误。 我究竟做错了什么? ARC 支持在 Xcode 中被关闭。 提前致谢。
如果您执行静态分析(Xcode 中的 shift+command+B,或 Xcode 的“产品”菜单中的“分析”) ,它会警告你在对象被释放后你正试图引用它:
问题在于,在手动引用计数代码中,您对已释放对象的引用不会自动设置为 nil
。因此,除非您手动 nil
这些指针,否则您最终可能会得到指向先前已释放的对象的悬空指针。
静态分析器非常擅长识别这类问题等。我建议您在继续之前确保静态分析仪的健康状况良好。
在这种情况下的第二道防线是启用僵尸运行时调试选项。这将报告在对象被释放后与对象交互的任何尝试。当您编辑 Xcode 目标的方案时,可以在“诊断”部分启用僵尸。
不幸的是,您使用的是 NSString
,它不遵循典型的内存管理规则(它可以保留自己对字符串的引用,因此它们并不总是在您期望的时候被释放他们是)。
考虑一个类似于你的例子,除了自定义类:
#import <Foundation/Foundation.h>
@interface MyObject: NSObject
@end
@implementation MyObject
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
MyObject *firstObject = [[MyObject alloc] init];
MyObject *secondObject = firstObject;
[firstObject release];
NSLog(@"%@", secondObject);
}
return 0;
}
如果您在启动僵尸的情况下运行此程序,您将收到一条相应的错误消息,表明您正在尝试与已释放的实例进行交互:
2017-05-27 08:19:18.154033-0700 MyApp[36888:7215135] *** -[MyObject isProxy]: message sent to deallocated instance 0x100303620
但您可能不会从 NSString
收到此警告。最重要的是,应该避免从 NSString
行为中得出任何更广泛的内存管理结论。相反,请依赖 Xcode 的静态分析器和僵尸程序。 (注意,当您完成应用程序的调试时,请记得关闭僵尸。)
关于ios - Xcode 8.3 中奇怪的 Clang 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44216327/
欢迎光临 OStack程序员社区-中国程序员成长平台 (https://ostack.cn/) | Powered by Discuz! X3.4 |