最近我注意到在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;
}
我认为, secondString 在释放 firstString 后指向 nil 并且 NSLog 会产生错误。 但是这段代码不会产生任何错误并成功打印出#34; Hello&#34;串。 我使用这样的命令手动编译和运行代码,并没有发现任何错误:
% clang -framework Foundation -fno-objc-arc main.m && ./a.out
我尝试使用在线Objective-c编译器(GCC)(http://rextester.com/l/objectivec_online_compiler)编译此代码,并且发生了错误。 我究竟做错了什么? 在Xcode中关闭ARC支持。 提前谢谢。
答案 0 :(得分:2)
如果在Xcode中执行静态分析( shift + 命令 + B ,或者在Xcode上执行&#34; Analyze&#34; #39; s&#34;产品&#34;菜单),它会警告您在对象发布后尝试引用该对象:
问题在于,在手动引用计数代码中,您对已解除分配对象的引用是不自动设置为import React, {Component} from 'react';
import ReactDOM from "react-dom";
var less = require('less');
var lessCss = require('./app.less');
console.log(lessCss); //output: /static/media/app.725ced4d.less
less.render(lessCss, function (e, output) {
console.log(e); //output: Unrecognized Input
console.log(output); //output: undefined
});
class Main extends Component {
/* render functions */
。因此,除非您手动nil
这些指针,否则您最终可能会暂停指向先前已取消分配的对象的指针。
静态分析仪非常擅长识别这些类型的问题。在继续之前,我建议您确保从静态分析仪中获得清洁的健康状况。
在这种情况下的第二道防线是启用僵尸运行时调试选项。这将报告在取消分配对象后与对象进行交互的任何尝试。可以在&#34;诊断&#34;中启用僵尸。编辑Xcode目标计划时的部分。
不幸的是,您使用的是nil
,它并不遵循典型的内存管理规则(它可以保留自己对字符串的引用,因此当您使用时,它们并不总是被释放。否则期望它们是。)
考虑一个类似于你的例子,除了自定义类:
NSString
如果您在僵尸打开的情况下运行此命令,则会收到相应的错误消息,指出您正在尝试与已解除分配的实例进行交互:
2017-05-27 08:19:18.154033-0700 MyApp [36888:7215135] *** - [MyObject isProxy]:消息发送到解除分配的实例0x100303620
但您可能无法从#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;
}
收到此警告。最重要的是,应该避免从NSString
行为中得出更广泛的记忆管理结论。相反,依靠Xcode的静态分析器和僵尸。 (注意,记得在你完成调试应用程序时关闭僵尸。)