如何重现罕见的“_CFAutoReleasePoolPop”崩溃?
How to reproduce a rare "_CFAutoReleasePoolPop" crash?
我正在尝试重现此类崩溃:
我的项目中有手动引用计数。此外,还有很多多线程。
一些属性不是线程安全的。 :(
关于这次崩溃的原因,我只有一个假设:某个对象被过度释放 (?)。
我已经添加了自动 UI 测试 (Appium
),但它们还没有帮助。
此外,我已经为 Zombies
进行了概要分析 - 一切似乎都很好。
另外,我试过 Xcode 的静态分析器( Product -> Analyze
),有很多警告,但其中 none 似乎是造成这种崩溃的原因(我'我看过警告 Incorrect decrement of reference count not owned at this point
).
我用MRC创建了一个测试项目,并添加了这样的代码:
- (void)testAssumptions {
//@autoreleasepool
{
[self overReleaseNilValue];
[self overReleaseNotNilValue];
}
}
- (void)overReleaseNilValue {
NSIndexPath* path = [[NSIndexPath alloc] initWithIndex:42];
[path release];
[path release];
}
- (void)overReleaseNotNilValue {
NSIndexPath* path = nil;
[path release];
[path release];
}
无论是否启用自动释放池,释放一个对象两次都不会崩溃。
所以我的问题是:
1. 除了释放已经释放的对象之外,这种崩溃的另一个原因是什么?
2. 有没有办法增加重现 此类崩溃的概率?例如。一些环境。减少一些自动释放池对不安全代码的容忍度的变量?或者一些额外的自动释放池?
3. 为什么我的测试项目代码没有崩溃?
非常感谢任何评论。
Incorrect decrement of reference count not owned at this point
这绝对是探索的警告。它几乎肯定会指出至少一个错误。
你的测试项目实际上并没有测试任何东西(我相信它们也是倒着命名的)。没有承诺过度释放一个值会导致崩溃。 overReleaseNotNilValue
是明确定义的行为,绝对不会崩溃(发送消息到 nil
什么都不做)。 overReleaseNilValue
是未定义的行为。我还没有深入研究它,但我希望 NSIndexPath
可以使用标记指针来实现,如果你过度释放它们,它不会崩溃。
未定义是未定义的。这并不意味着崩溃。过度释放一个值可以做任何事情。如果你运气好,它会崩溃....
Also, there's a lot of multi-threading. Some of the properties are not thread-safe.
如果它是间歇性的,我希望这是您问题的核心。我从事过这样的项目。解决方案是解决问题。您不会知道是哪个具体问题导致了崩溃。你可能永远不知道。您仍然必须修复它们。这需要一些时间,但你必须使代码线程安全,否则它的行为是未定义的。
关于调试,您需要按顺序执行以下操作:
打开运行时间清理选项(在方案编辑器下,运行,诊断)。为此,您尤其需要 Thread Sanitizer。
清除所有静态分析器警告。如果其中任何一个说您的内存管理有误,您必须清除它们。该系统实际上是在告诉您问题出在哪里。不要忽视它。
清除所有警告。您的项目中应该有零警告。如果有很多 "false" 警告,那么您将永远看不到真正的警告,告诉您问题出在哪里。消除所有警告。
我花了 8 个月的时间消除了一个由专家开发人员编写且几乎没有线程的精心编写的项目中罕见的过度发布崩溃。这可能需要很多时间。你必须清除每一个问题。一个不正确的版本就足以让程序随机崩溃。
我正在尝试重现此类崩溃:
我的项目中有手动引用计数。此外,还有很多多线程。
一些属性不是线程安全的。 :(
关于这次崩溃的原因,我只有一个假设:某个对象被过度释放 (?)。
我已经添加了自动 UI 测试 (Appium
),但它们还没有帮助。
此外,我已经为 Zombies
进行了概要分析 - 一切似乎都很好。
另外,我试过 Xcode 的静态分析器( Product -> Analyze
),有很多警告,但其中 none 似乎是造成这种崩溃的原因(我'我看过警告 Incorrect decrement of reference count not owned at this point
).
我用MRC创建了一个测试项目,并添加了这样的代码:
- (void)testAssumptions {
//@autoreleasepool
{
[self overReleaseNilValue];
[self overReleaseNotNilValue];
}
}
- (void)overReleaseNilValue {
NSIndexPath* path = [[NSIndexPath alloc] initWithIndex:42];
[path release];
[path release];
}
- (void)overReleaseNotNilValue {
NSIndexPath* path = nil;
[path release];
[path release];
}
无论是否启用自动释放池,释放一个对象两次都不会崩溃。
所以我的问题是:
1. 除了释放已经释放的对象之外,这种崩溃的另一个原因是什么?
2. 有没有办法增加重现 此类崩溃的概率?例如。一些环境。减少一些自动释放池对不安全代码的容忍度的变量?或者一些额外的自动释放池?
3. 为什么我的测试项目代码没有崩溃?
非常感谢任何评论。
Incorrect decrement of reference count not owned at this point
这绝对是探索的警告。它几乎肯定会指出至少一个错误。
你的测试项目实际上并没有测试任何东西(我相信它们也是倒着命名的)。没有承诺过度释放一个值会导致崩溃。 overReleaseNotNilValue
是明确定义的行为,绝对不会崩溃(发送消息到 nil
什么都不做)。 overReleaseNilValue
是未定义的行为。我还没有深入研究它,但我希望 NSIndexPath
可以使用标记指针来实现,如果你过度释放它们,它不会崩溃。
未定义是未定义的。这并不意味着崩溃。过度释放一个值可以做任何事情。如果你运气好,它会崩溃....
Also, there's a lot of multi-threading. Some of the properties are not thread-safe.
如果它是间歇性的,我希望这是您问题的核心。我从事过这样的项目。解决方案是解决问题。您不会知道是哪个具体问题导致了崩溃。你可能永远不知道。您仍然必须修复它们。这需要一些时间,但你必须使代码线程安全,否则它的行为是未定义的。
关于调试,您需要按顺序执行以下操作:
打开运行时间清理选项(在方案编辑器下,运行,诊断)。为此,您尤其需要 Thread Sanitizer。
清除所有静态分析器警告。如果其中任何一个说您的内存管理有误,您必须清除它们。该系统实际上是在告诉您问题出在哪里。不要忽视它。
清除所有警告。您的项目中应该有零警告。如果有很多 "false" 警告,那么您将永远看不到真正的警告,告诉您问题出在哪里。消除所有警告。
我花了 8 个月的时间消除了一个由专家开发人员编写且几乎没有线程的精心编写的项目中罕见的过度发布崩溃。这可能需要很多时间。你必须清除每一个问题。一个不正确的版本就足以让程序随机崩溃。