Adobe iOS SDK在引用写到plist文件返回前台时崩溃



我在复制下面详细的崩溃时遇到了麻烦(从崩溃分析/跟踪中得到的)。在报告的每个崩溃实例中,似乎总是有另一个可疑的线程在崩溃线程的旁边同时运行:

撞线

0   CoreFoundation 0x2f9074be CFGetTypeID + 6
1   CoreFoundation 0x2f91e47b _flattenPlist + 47
2   CoreFoundation 0x2f91e57f _flattenPlist + 307
3   CoreFoundation 0x2f98257b __CFBinaryPlistWrite + 131
4   CoreFoundation 0x2f91e321 CFPropertyListWrite + 245
5   CoreFoundation 0x2f92e731 CFPropertyListWriteToStream + 145
6   CoreFoundation 0x2f92c39d _CFXPreferencesWritePlist + 269
7   CoreFoundation 0x2f92c28b -[CFXPreferencesPropertyListSourceSynchronizer writePlistToDisk] + 131
8   CoreFoundation 0x2f929aef -[CFXPreferencesPropertyListSourceSynchronizer synchronizeAlreadyFlocked] + 487
9   CoreFoundation 0x2f929905 -[CFXPreferencesPropertyListSourceSynchronizer synchronize] + 21
10  CoreFoundation 0x2f929405 __79-[CFXPreferencesPropertyListSource synchronizeInBackgroundWithCompletionBlock:]_block_invoke + 101
11  libdispatch.dylib 0x3a656d53 _dispatch_call_block_and_release + 11
12  libdispatch.dylib 0x3a65bcbd _dispatch_queue_drain + 489
13  libdispatch.dylib 0x3a658c6f _dispatch_queue_invoke + 43
14  libdispatch.dylib 0x3a65c5f1 _dispatch_root_queue_drain + 77
15  libdispatch.dylib 0x3a65c8dd _dispatch_worker_thread2 + 57
16  libsystem_pthread.dylib 0x3a787c17 _pthread_wqthread + 299
17  libsystem_pthread.dylib 0x3a787adc start_wqthread + 8

其他可疑线程(总是同时运行并且看起来是相关的):

0   libsystem_kernel.dylib 0x3a70faa0 semaphore_wait_trap + 8
1   libdispatch.dylib 0x3a65b513 _dispatch_barrier_sync_f_slow + 139
2   CoreFoundation 0x2f94424d CFPreferencesAppSynchronize + 265
3   Foundation 0x3032e91d -[NSUserDefaults(NSUserDefaults) synchronize] + 25
4   MailOnline 0x00280897 ADBLifecycleStart + 2495
5   CoreFoundation 0x2f998f41 _CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 13
6   CoreFoundation 0x2f90cda9 _CFXNotificationPost + 1721
7   Foundation 0x302f7cc5 -[NSNotificationCenter postNotificationName:object:userInfo:] + 73
8   UIKit 0x3246747f -[UIApplication _sendWillEnterForegroundCallbacks] + 155
9   UIKit 0x3240c88b -[UIApplication _handleApplicationResumeEvent:] + 927
10  UIKit 0x3220b613 -[UIApplication handleEvent:withNewEvent:] + 1883
11  UIKit 0x3220adf9 -[UIApplication sendEvent:] + 73
12  UIKit 0x3226f405 _UIApplicationHandleEvent + 617
13  GraphicsServices 0x34878b55 _PurpleEventCallback + 609
14  GraphicsServices 0x3487873f PurpleEventCallback + 35
15  CoreFoundation 0x2f9a1847 _CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 35
16  CoreFoundation 0x2f9a17e3 __CFRunLoopDoSource1 + 347
17  CoreFoundation 0x2f99ffaf __CFRunLoopRun + 1407
18  CoreFoundation 0x2f90a769 CFRunLoopRunSpecific + 525
19  CoreFoundation 0x2f90a54b CFRunLoopRunInMode + 107
20  GraphicsServices 0x348776d3 GSEventRunModal + 139
21  UIKit 0x32269891 UIApplicationMain + 1137
22  MailOnline 0x000cd18b main (main.m:16)
23  libdyld.dylib 0x3a66bab7 start + 3

当调试正在运行的程序时,我们用于跟踪的Adobe Mobile SDK似乎侦听由操作系统触发的返回前台事件,然后在NSUserDefaults上调用synchronize(参见其他可疑线程)。然后同步中断到另一个线程(崩溃的线程),但是当试图写入plist文件时,由于某种原因它崩溃了。

我无法重现崩溃。我们使用的是Adobe Mobile Library iOS SDK的4.0版本,所以如果其他人使用这些SDK有类似的崩溃,请帮助!或者如果有人有任何建议的步骤,使这种崩溃更有可能发生(例如,我已经尝试编写plist不断当SDK运行,看看它是否是一个线程问题,但没有运气),然后请建议…

注意:此问题仍然发生在运行iOS 7的新设备上,但仍然不会发生在运行iOS 8.0或8.1的设备上。

这个问题是由于NSUserDefaults本身内部的竞争条件。下面的代码片段将在一个孤立的场景中再现该问题(您需要让该代码运行15-30秒以暴露该问题):

dispatch_async(dispatch_get_main_queue(), ^{
        while(true) {
            for(int i = 0; i < 20000; i++) {
                [[NSUserDefaults standardUserDefaults] setObject: @"value" forKey: [NSString stringWithFormat: @"blah%d",i]];
            }
            for(int i = 0; i < 20000; i++) {
                [[NSUserDefaults standardUserDefaults] removeObjectForKey: [NSString stringWithFormat: @"blah%d",i]];
            }
        }
    });

其他人也报告了这个问题,最明显的例子是苹果开发者论坛上的这篇文章(需要注册)。

我的建议是检查你的代码是否有任何重要的读/写周期进入NSUserDefaults。如果你需要对数据做大量的更改或更新,你可能想要滚动你自己的持久层,而不是NSUserDefaults,直到这个问题被苹果解决。

ADBLifecycleStart方法在这个场景中是一个转移注意力的方法。这段代码在它自己的队列上运行,并且大多数时候可能是活的(或者至少被一个完整的线程转储捕获)。ADBLifeCycleStart方法在最坏的情况下总共有13次写入NSUserDefaults,然后是一次同步。

注意:在今年的WWDC上,苹果工程师证实NSUserDefaults得到了全面重写。经过一些测试,这个问题似乎已经解决,并且在iOS 8中不再出现。

Henry

在启动时,sdk更新存储在NSUserDefaults中的一些项。在这些项目被更新之后,NSUserDefaults尝试同步更新NSUserDefaults列表。当设备试图更新plist时,看起来应用程序正在崩溃。经过一些调查,似乎这可能有几个不同的原因。1)如果僵尸模式被打开(导致内存永远不会被释放),你的应用程序达到每进程4GB, 2) nsuserdefaults列表已经损坏。

猎人

最新更新