这是来自Crashlytics的两个堆栈跟踪,都包含我的代码的同一行,但导致两次不同的崩溃。
# OS Version: 10.3.2 (14F90)
# Device: iPad 5
# RAM Free: 3.8%
# Disk Free: 90.7%
#0. Crashed: com.apple.main-thread
0 libsystem_platform.dylib 0x18d365090 _platform_memset + 126
1 libsystem_malloc.dylib 0x18d2ebd00 _nano_malloc_check_clear + 584
2 libsystem_malloc.dylib 0x18d2eacb0 nano_calloc + 80
3 libsystem_malloc.dylib 0x18d2dc4e8 malloc_zone_calloc + 168
4 libsystem_malloc.dylib 0x18d2dc41c calloc + 40
5 libobjc.A.dylib 0x18cd18160 class_createInstance + 76
6 CoreFoundation 0x18e2b2928 __CFAllocateObject + 28
7 CoreFoundation 0x18e29c064 +[__NSSingleObjectArrayI __new::] + 28
8 CoreFoundation 0x18e18cd18 -[NSArray initWithArray:range:copyItems:] + 400
9 MyApp 0x10010003c -[ConstituentDownload currentProgress] (ConstituentDownload.m:117)
10 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
11 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
12 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
13 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
14 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
15 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
16 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
17 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
18 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
19 MyApp 0x1001000b4 -[ConstituentDownload currentProgress] (ConstituentDownload.m:118)
20 MyApp 0x100100234 -[ConstituentDownload sendProgressNotification] (ConstituentDownload.m:141)
... button press stuff...
和:
# OS Version: 10.3.1 (14E304)
# Device: iPad 4
# RAM Free: 4.7%
# Disk Free: 12.2%
#0. Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x1bc38692 objc_retain + 1
1 CoreFoundation 0x1c8acf39 +[__NSArrayI __new:::] + 74
2 CoreFoundation 0x1c8ae9f1 -[__NSArrayM copyWithZone:] + 174
3 MyApp 0x189407 -[ConstituentDownload currentProgress] (ConstituentDownload.m:117)
4 MyApp 0x18999f -[ConstituentDownload userInfoForProgressNotification] (ConstituentDownload.m:180)
5 MyApp 0x189611 -[ConstituentDownload sendProgressNotification] (ConstituentDownload.m:144)
...button press stuff...
这是导致崩溃的方法:
- (float)currentProgress {
float sections = [self.childDownloads count] + 1;
float referencedProgress = 0.;
// This line causes the crash - where we copy the property array
for(ConstituentDownload *d in [self.childDownloads copy]) {
referencedProgress += d.currentProgress;
}
float progress = (super.currentProgress + referencedProgress) / sections;
return progress;
}
self.childDownloads
是一个NSMutableArray,其中包含与该方法存在的类型相同的对象:ConstituentDownload
。它可以从其他线程访问,并且可以添加元素,这就是为什么我在对其进行迭代之前首先将其复制的原因。该数组中往往包含0-20个对象。即使我在这里复制它,也可能是由于在另一个线程中对数组进行了变异而导致此崩溃吗?
可能是某种内存损坏引起的吗?如果是这样,您能为我指出正确的方向吗?
可能是由于设备上的RAM用完了吗?如果是这样,为什么不将其报告为内存不足错误而不是生成崩溃报告?
是的,从某种意义上说,该方法是递归的。父
ConstituentDownload
在其每个子下载中都调用currentProgress
,后者又在其每个子下载中调用ojit_code。崩溃堆栈中有时只有1个递归调用,有时大约是10个左右,如这两个崩溃堆栈所示。只有在运行iOS 9和iOS 10的设备上才看到此崩溃,但这可能是因为几乎我的所有用户都在这两个OS版本上。
无论如何,KERN_PROTECTION_FAILURE是什么意思?
最佳答案
我找不到准确说明它的特定参考,但是我认为您应该假设以这种方式复制可变数组并不安全。
一般而言,在一个线程中对NSMutableArray
进行迭代(而从另一个线程进行突变)是不安全的。无论在后台如何实现copy
,它都必须以某种方式遍历数组以完成其工作。
根据您的描述,听起来您可能正在从多个不同的线程中添加/删除项目。您是否正在使用某种锁定或序列化来使该线程安全?如果不是,那也可能导致崩溃在此时发生。
如果是这样,则应使用相同的锁定来保护此copy
操作。