2017-02-28 13 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にそのMOCのために保存する呼び出しに応答するように要求するときにPSCがロックされていることを示します。

    私の謙虚な意見では、はまだになります。performBlockに電話している可能性があります。このコードでは、フェッチ要求を実行してからプロパティを更新し、そのオブジェクトをMOCに挿入してから、同じブロックにすべて保存します。これらは非常に異なる機能で、処理能力と時間がそれぞれ異なり、すべてが1つの同時実行ブロックにダンプされます。

    また、並行性とブロックを使用するときにプロパティをインスタンス化する方法も重要です。プロパティをインスタンス化するために、コードのどこが最も適切かを確認する必要があります。

    だから、いくつかの質問には...

    1. あなたはperformBlockでこのコードのすべての行は必要ですか?あなたのUIをブロックしていない限り、フェッチ要求とあなたのプロパティへの更新は、performBlockの呼び出しの外のコードでは問題ありません。
    2. このコードのすべての行がperformBlockなどのコアデータ並行処理ブロックに必要な場合は、代わりにsaveへの呼び出しを「ブロック内ブロック」に埋め込み、performBlockAndWaitを使用すると考えましたか?

    Apple developer websiteperformBlockAndWaitブロックにsaveコールを埋め込む例があり、含まれ、次の(一部):

    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用コアデータ、第2版、データストレージおよび管理」で説明されています、OS X、iCloud」(Marcus S. Zarra著、The Pragmatic Bookshelfの2013年1月)、特に第4章「パフォーマンスチューニング」と第5章「スレッディング」を参照してください。

    Apressの出版社のコアデータに関するもう1つの貴重な本 - マイケル・プリヴァートとロバート・ワーナーによる「コアデータを使用したiOSの永続性」

    +0

    お返事ありがとうございます。 私は、私が上記で参照した 'コンテキスト'オブジェクトが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で修正されたと仮定します。

    関連する問題