自iOS 10以来发生核心数据崩溃

时间:2017-02-28 22:03:42

标签: objective-c core-data ios10

我一直在努力解决自sqlite / coredata库中iOS 10以来本地无法再生的崩溃。它很少发生 - 在生产中0.2%的范围内。

我所知道的(或至少是怀疑的):

  • 仅在iOS 10及以上版本中发生。
  • 通常在保存上下文时发生,但也可能在核心数据获取请求期间发生。
  • 很少发生(球场比率为0.15%)
  • 我运行了启用了并发调试标志的压力测试,以及一些xcode内存管理工具。没有发现问题。
  • 针对内存泄漏进行了测试。
  • 我从来没有能够在开发环境中重现这种堆栈跟踪。
  • 在崩溃之前没有抛出异常。整个代码都被包装好了。
  • 此操作在块内执行,应用程序位于前台。
  • 在正常的应用操作期间似乎随机发生。 (不是在初始化时或任何特殊情况)
  • 这是一次SIGABRT崩溃
  

libsystem_kernel.dylib0x00000001841c3014 __pthread_kill + 4       libsystem_c.dylib0x0000000184137400 abort + 136       libsystem_malloc.dylib0x0000000184207a5c nanozone_error + 328       libsystem_malloc.dylib0x0000000184209028 nano_realloc + 644       libsystem_malloc.dylib0x00000001841fb240 malloc_zone_realloc + 176       libsqlite3.dylib0x0000000185730c34 sqlite3_value_text + 1220       libsqlite3.dylib0x0000000185777f38 sqlite3_rekey + 1564       libsqlite3.dylib0x000000018578df78 sqlite3_rekey + 91740       libsqlite3.dylib0x0000000185791c88 sqlite3_rekey + 107372       libsqlite3.dylib0x000000018571df98 sqlite3_log + 86448       libsqlite3.dylib0x0000000185757780 sqlite3_bind_int + 11992       libsqlite3.dylib0x00000001856f1c80 sqlite3_exec + 35188       libsqlite3.dylib0x00000001856eb608 sqlite3_exec + 8956       libsqlite3.dylib0x00000001856ea838 sqlite3_exec + 5420       libsqlite3.dylib0x00000001856e9f24 sqlite3_exec + 3096       libsqlite3.dylib0x00000001856e9ae0 sqlite3_exec + 2004       CoreData0x00000001874f1284 - [NSSQLiteConnectionprepareSQLStatement:] + 468       CoreData0x00000001876166f0 - [NSSQLiteConnectionupdateRow:forRequestContext:] + 496       CoreData0x00000001876c3430 _writeChangesForSaveRequest + 1596       CoreData0x00000001876c4958 _executeSaveChangesRequest + 312       CoreData0x00000001876ba7f4 - [NSSQLSaveChangesRequestContextexecuteRequestUsingConnection:] + 40       CoreData0x00000001875cdaf8 __52- [NSSQLDefaultConnectionManagerhandleStoreRequest:] _ block_invoke + 256       libdispatch.dylib0x000000018407e1bc _dispatch_client_callout + 12       libdispatch.dylib0x000000018408b7f0 _dispatch_barrier_sync_f_invoke + 80       CoreData0x00000001875cd994 - [NSSQLDefaultConnectionManagerhandleStoreRequest:] + 204       CoreData0x0000000187693f80 - [NSSQLCoreDispatchManagerrouteStoreRequest:] + 284       CoreData0x00000001875fb7e4 - [NSSQLCoredispatchRequest:withRetries:] + 196       CoreData0x00000001875f7560 - [NSSQLCoreprocessSaveChanges:forContext:] + 200       CoreData0x00000001874f8360 - [NSSQLCoreexecuteRequest:withContext:error:] + 744       CoreData0x00000001875da2f4 __65- [NSPersistentStoreCoordinatorexecuteRequest:withContext:error:] _ block_invoke + 3248       CoreData0x00000001875d2bf0 - [NSPersistentStoreCoordinator_routeHeavyweightBlock:] + 272       CoreData0x00000001874f7f20 - [NSPersistentStoreCoordinatorexecuteRequest:withContext:error:] + 404       CoreData0x00000001875195ac - [NSManagedObjectContextsave:] + 2768

这是代码通常的样子:

NSManagedObject *object = [[MyManagedObject alloc] init];

// This is actually within the init method
NSEntityDescription *desc = [NSEntityDescription entityForName:NSStringFromClass(object.class)
                                      inManagedObjectContext:context];

[object initWithEntity:desc insertIntoManagedObjectContext:nil];


// later on...
[context performBlock:^{

    // Fetch another (different) object from core data
    NSArray *fetchResults = [context executeFetchRequest:request error:&error];

    // Changing some properties of object with values from fetched results
    object.property = fetchResults[0].property;

    // insert the object
    [context insertObject:object];

    // save the context
    [context save:&error]
}

非常感谢任何想法。

更新

我发现此发行说明与iOS 10.2一致,这可能导致一些现有问题暴露。目前尚不清楚变化是什么,或者它可能如何导致问题,但看起来这很可能是以某种方式相关的。

https://support.apple.com/en-us/HT207422 影响:处理恶意字符串可能会导致意外的应用程序终止或任意代码执行 说明:字符串处理中存在内存损坏问题。通过改进的边界检查解决了这个问题。 CVE-2016-7663

2 个答案:

答案 0 :(得分:1)

如果大部分代码库都是异步的,并且您尝试在此异步块中执行同步保存操作,那么您有充分的理由怀疑这就是您接收{{{ 1}}错误消息中的错误。

关键是NSPersistentStoreCoordinator(PSC)无法正确协调数据保存的问题。除非我弄错了,否则当您要求PSC响应为该MOC保存的呼叫时,错误消息会识别PSC被锁定。

我个人认为你的问题仍然很可能源于你对NSPersistentStoreCoordinator的呼吁......在这段代码中你执行了获取请求,然后更新了一个属性,然后将对象插回MOC,然后保存,全部在同一个块中。这些是非常不同的函数,它们采用不同的处理能力和时间,都被转储到一个单独的并发块中。

此外,在使用并发和块时如何实例化属性非常重要。您可能需要检查代码中最适合实例化属性的位置。

所以有些问题......

  1. 您是否需要在performBlock中使用此代码的每一行?请注意,除非您阻止自己的用户界面,否则在performBlock调用之外的代码中,获取请求和对您的媒体资源的更新可能正常。
  2. 如果确实需要核心数据并发块(例如performBlock)中此代码的每一行,您是否考虑过将您的呼叫嵌入到{... 1}中的"块内...嵌段"并使用performBlock
  3. Apple developer website有一个将save调用嵌入performBlockAndWait块的示例,其中包含(部分)以下内容:

    save

    如果您能够使用更多代码和更详细的说明更新您的问题,我可以为您的具体问题提供更准确的解决方案。

    我也建议你做一些研究......

    尽管本书时代已经存在,但并发性概念仍然在“核心数据,第2版,iOS数据存储和管理”,“OS X”和“iCloud”中得到了很好的解释。 (2013年1月,来自The Pragmatic Bookshelf)由Marcus S. Zarra撰写,特别是第4章标题为“性能调整”和第5章标题为“#34;线程”。

    关于Apress出版商核心数据的另一本有价值的书 - " Pro Pro Persistence Using Core Data",作者:Michael Privat和Robert Warner。

答案 1 :(得分:0)

从iOS 10.3开始不再出现。根本原因尚不清楚。假设一些iOS内存管理在10.2中中断,修复为10.3。