2017-02-28 57 views
2

我一直在努力解決自sqlite/coredata庫內的iOS 10以來本地不可重現的崩潰。這種情況很少發生 - 在0.2%的生產領域。自從iOS 10發生核心數據崩潰

我所知道的(或至少嫌疑人):

  • 它只發生在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

+0

核心數據上下文對於讀取或寫入都不是線程安全的。如果您違反此核心數據,可能會隨時以任何方式失敗。這意味着即使在正確的線程中的代碼中的某些點,它也可能很難診斷崩潰報告。我會檢查你的代碼是否存在線程安全違規。我將首先查看將managedObjects作爲參數傳遞的任何函數。 –

+0

感謝您的意見。我在測試應用程序時使用併發標誌'-com.apple.CoreData.ConcurrencyDebug 1',並且它沒有標記最新版本中的任何內容。我還手動梳理了代碼,因爲我最初也懷疑併發問題。不幸的是,儘管如此,這個錯誤仍然在發生。 – Kieran

+0

如果它只發生在0.5%的構建中,則代碼行(或者情況組合)可能非常少見,並且很難通過行使代碼來找到。有時代碼審查可以做更多的事情來發現這些問題。 –

回答

1

如果您的大部分代碼庫如您所說的那樣是異步的並且您試圖在此異步塊中執行同步保存操作,那麼您有充分的理由懷疑這就是爲什麼您的「重新收到錯誤消息中的NSPersistentStoreCoordinator錯誤。

關鍵是NSPersistentStoreCoordinator(PSC)未能正確協調數據保存的問題。除非我錯誤,否則錯誤消息表明PSC在您要求PSC響應保存該MOC的呼叫時鎖定了PSC。

在我的愚見你的問題仍然最有可能源於你的電話performBlock ...在此代碼中,您正在執行提取請求,然後更新屬性,然後將對象插回到MOC中,然後將其保存在同一個塊中。這些功能是非常不同的功能,它們將不同的處理能力和時間花費在一個併發塊上。

另外,如何在使用併發性和塊時實例化屬性非常重要。您可能需要檢查代碼中最適合實例化屬性的位置。

所以有些問題...

  1. 你需要在這個performBlock代碼的每一行?請考慮,除非您阻止了您的用戶界面,否則在撥打performBlock之外的代碼中,您的媒體資源的獲取請求和更新可能會正常。
  2. 如果您確實需要核心數據併發塊(如performBlock)中的此代碼的每一行,您是否考慮過將嵌入呼叫save嵌入到「block-in-a-block」中並使用performBlockAndWait

Apple developer website具有嵌入save呼叫轉變爲performBlockAndWait塊的例子,包括(部分)如下:

NSManagedObjectContext *moc = '…; //Our primary context on the main queue 

NSManagedObjectContext *private = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
[private setParentContext:moc]; 

[private performBlock:^{ 
    'Complete your fetch request and update the managed object's property. 

    NSError *error = nil; 
    if (![private save:&error]) { 
     NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]); 
     abort(); 
    } 
    [moc performBlockAndWait:^{ 
     NSError *error = nil; 
     if (![moc save:&error]) { 
      NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]); 
      abort(); 
     } 
    }]; 
}]; 

如果你能多一點代碼來更新你的問題,更詳細的描述我可能能夠爲您的具體問題提供更準確的解決方案。

而且我建議你做一些研究...

儘管這本書的時代,併發的概念仍然相當不錯,在「核心數據,第二版,數據存儲和管理爲iOS解釋,OS X和iCloud「(2013年1月來自The Pragmatic Bookshelf)Marcus S. Zarra,特別是第4章標題爲」性能調優「和第5章標題爲」Threading「。

Michael Privat和Robert Warner撰寫的關於Apress出版商的核心數據的另一本有價值的書籍 - 「Pro iOS持久性使用核心數據」。

+0

感謝您的迴應。 我應該提到我上面提到的'context'對象是一個私有管理對象上下文,已經有了PrivateQueueConcurrencyType。大部分代碼庫與主隊列是獨立的和異步的。在這個原因中,我不認爲雙塊會真的獲得我們的任何東西(雖然這肯定是一個有趣的概念) – Kieran

+0

我也發現(自從我發佈這個昨天),有類似的內存問題報告獨立核心報告的數據在這裏: https://forums.developer.apple.com/message/207825 這裏: https://forums.developer.apple.com/thread/63546 我開始懷疑蘋果iOS10內存管理問題。 – Kieran

+0

我可能會誤解你的情況,但我相信你有很多可以從包括雙塊。查看更新的答案。 – andrewbuilder

0

從iOS 10.3開始不再發生。根本原因尚不清楚。假設一些iOS內存管理在10.2中斷,修復爲10.3。