简单的Objective-C过度释放 *应该 *崩溃不会崩溃。为什么?
-
28-09-2019 - |
题
我的调试器要么破坏,要么有一些我不理解的基本内容。
我在一个非常基本的命令行程序中有一些非常基本的代码 应该 碰撞。但是,它并没有崩溃。
int main (int argc, const char * argv[])
{
NSString *string = [[NSString alloc] initWithString:@"Hello"];
[string release];
NSLog(@"Length: %d", [string length]);
return 0;
}
日志语句打印“长度:5”,如您所期望的有效字符串。但是,该字符串应以此为由 exec_bad_access
错误应丢弃。
我尝试使用附加的调试器,没有附加的调试器 - 都给出相同的结果。我还启用了(和禁用) NSZombie
, ,这似乎没有效果(我最初认为这是问题,因为 NSZombie
物体永远不会被划分 - 但仍然不会崩溃 NSZombie
禁用)。
我在本地设置了断点 .gdbinit
档案破坏诸如 -[NSException raise]
和 objc_exception_throw
. 。我在许多方法上也设置了断点 NSZombie
为了抓住他们。
fb -[NSException raise]
fb -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:]
fb -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
#define NSZombies
# this will give you help messages. Set to NO to turn them off.
set env MallocHelp=YES
# might also be set in launch arguments.
set env NSZombieEnabled=YES
set env NSDeallocateZombies=NO
set env MallocCheckHeapEach=100000
set env MallocCheckHeapStart=100000
set env MallocScribble=YES
set env MallocGuardEdges=YES
set env MallocCheckHeapAbort=1
set env CFZombie 5
fb -[_NSZombie init]
fb -[_NSZombie retainCount]
fb -[_NSZombie retain]
fb -[_NSZombie release]
fb -[_NSZombie autorelease]
fb -[_NSZombie methodSignatureForSelector:]
fb -[_NSZombie respondsToSelector:]
fb -[_NSZombie forwardInvocation:]
fb -[_NSZombie class]
fb -[_NSZombie dealloc]
fb szone_error
fb objc_exception_throw
这些断点设置并启用了NSZOMBIE,我应该得到类似的东西 [NSString length]: message sent to deallocated instance 0x100010d39
印刷到控制台,但我看不到。我明白了 NSLog
将长度打印为5。
我看到了与其他类别的类似行为 NSURL
和 NSNumber
. 。但是有些课程崩溃了,例如 NSError
和 NSObject
.
这与班级集群有关吗?对于内存管理,他们是否遵守相同的规则?
如果类别簇与此问题无关,我可以看到的唯一其他常见功能是,以这种方式崩溃的类都是与核心基础相对方的免费桥接。这可能与它有关吗?
解决方案
retain
/release
是API和程序员之间的合同,当您遵守规则时,它不会崩溃。合同不能保证,如果您不遵守规则,它确实会崩溃!
在这种情况下,
[[NSString alloc] initWithString:@"Hello"]
只是返回与 @"Hello"
作为优化。常数 NSString
永远不会被划分;作为优化, retain
和 release
(我认为)被忽略。这就是为什么它不会崩溃。
您可以通过比较指针值来检查我的猜测 @"Hello"
和 string
.
其他提示
这是一个很好的例子,说明为什么保留计数是一种毫无用处的调试工具。假设 - 固定和 - 弹力始终从保留计数中添加或删除1是一个错误,并且您认为保留计数是您认为应该是的。
尝试
NSString *string = [[NSString alloc] initWithFormat:@"Hello %d", argc];
这应该给您一个琴弦,它的行为会更像您期望的方式,因为您没有从编译时间常数初始化字符串。但是,请注意,通过启用僵尸,您将获得您期望的行为,但是如果没有僵尸,NSLOG可能会起作用。尽管该字符串已被划定,但对象中的数据仍在存储器中,留下了“幽灵”,该数据将正确响应某些消息。