0

我正在尝试重现此类崩溃: 在此处输入图像描述

我的项目中有手动引用计数。此外,还有很多多线程。有些属性不是线程安全的。:(
我对这次崩溃的原因只有一个假设:某些对象被过度释放(?)

我添加了自动化 UI 测试 ( Appium),但它们还没有帮助。
此外,我已经分析了Zombies- 一切似乎都很好。
另外,我尝试过 Xcode 的静态分析器(Product -> Analyze),有很多警告,但似乎都不是导致此类崩溃的原因(我已经查看了警告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. 为什么我的测试项目代码没有崩溃?

任何意见都受到高度赞赏。

4

1 回答 1

2

此时不拥有的引用计数的不正确递减

这绝对是值得探索的警告。几乎可以肯定,它至少会指出一个错误。

您的测试项目实际上并没有测试任何东西(我相信它们也被向后命名)。没有保证过度释放一个值会导致崩溃。overReleaseNotNilValue是定义明确的行为,并且绝对不会崩溃(发送消息nil什么都不做)。overReleaseNilValue是未定义的行为。我还没有深入研究它,但我希望NSIndexPath用标记的指针来实现,如果你过度释放它们就不会崩溃。

未定义就是未定义。这并不意味着崩溃。过度释放一个值可以做任何事情。如果幸运的话,它会崩溃......

此外,还有很多多线程。有些属性不是线程安全的。

如果它是间歇性的,我希望这将成为您问题的核心。我从事过这样的项目。解决方案是解决问题。您将不知道导致崩溃的具体问题。你可能永远不会知道。你仍然必须修复它们。这将需要一些时间,但您必须使代码线程安全,否则它的行为是未定义的。

至于调试,您需要按顺序执行以下操作:

  • 打开运行时清理选项(在方案编辑器、运行、诊断下)。为此,您尤其需要 Thread Sanitizer。

  • 清除所有静态分析器警告。如果他们中的任何一个说你的内存管理是错误的,你必须清除那些。该系统实际上是在告诉您问题出在哪里。不要忽视它。

  • 清除所有警告。您的项目中应该有零警告。如果有很多“错误”警告,那么您将永远不会看到真正的警告告诉您问题出在哪里。消除所有警告。

我花了 8 个月的时间在一个由专家开发人员编写的精心编写的项目中消除了罕见的过度发布崩溃,并且几乎没有线程。这可能需要很多时间。你必须清除每一个问题。仅仅一个不正确的版本就足以使程序随机崩溃。

于 2019-10-28T20:30:39.907 回答