2017-07-24 48 views
0

我在一個已發佈的應用程序中偶然發生崩潰,並從崩潰報告知道它發生在哪一行以及崩潰類型 - EXC_BAD_ACCESS(SIGSEGV)KERN_INVALID_ADDRESS - 但我不知道如何內存可能會變得無效,因爲被引用的對象的生命週期是應用程序的生命週期,並且除非應用程序終止,否則不會被刪除。因此,如果崩潰不是由於訪問已刪除的內存造成的(因爲該內存未被刪除),在這種特殊情況下EXC_BAD_ACCESS會有什麼其他原因?EXC_BAD_ACCESS KERN_INVALID_ADDRESS但內存未被刪除

下面的代碼:

@interface Model() 
@property (strong, nonatomic) NSMutableDictionary* cityAndStateDictionary; 
@end 


- (NSString*) findAddress: (NSString*) key 
{ 
    if (key == nil) 
    { 
     return nil; 
    } 
    NSString* cityAndState = (self.cityAndStateDictionary)[key]; // Crash here 
} 



@implementation Model 
- (id) init 
{ 
    self = [super init]; 
    if (self) 
    { 
     dispatch_async(modelQueue(), ^{ 
      [self readCityAndStateData]; 
     }); 
    } 
} 


- (void) readCityAndStateData 
{ 
    NSBundle* bundle = [NSBundle bundleForClass:[Model class]]; 
    NSString *filePath = [bundle pathForResource:@"CityState" ofType:@"json"]; 
    NSData *data = [NSData dataWithContentsOfFile:filePath]; 
    NSError* __autoreleasing nserror; 
    NSDictionary* jsonParser = [NSJSONSerialization JSONObjectWithData: data 
                   options: NSJSONReadingAllowFragments 
                   error: &nserror]; 
    if (nserror == nil) 
    { 
     self.cityAndStateDictionary = [[NSMutableDictionary alloc] init]; 
     for (NSDictionary *item in jsonParser) 
     { 
      // create value object 
      (self.cityAndStateDictionary)[key] = value; 
     } 
    } 
} 

readCityAndStateData()正在創建一個線程內填充,如果findAddress()已完成之前被稱爲然後cityAndStateDictionary將是零,所以在findAddress調用(self.cityAndStateDictionary)[key]也只是零。 cityAndStateDictionary對象是而不是被刪除的任何地方,因此崩潰不應該由於訪問已刪除的內存。

墜機的原因是什麼?

Exception Type: EXC_BAD_ACCESS (SIGSEGV) 
Exception Subtype: KERN_INVALID_ADDRESS at 0x000000010624ae60 
Termination Signal: Segmentation fault: 11 
Termination Reason: Namespace SIGNAL, Code 0xb 
Terminating Process: exc handler [0] 
Triggered by Thread: 0 

Thread 0 name: 
Thread 0 Crashed: 
0 CoreFoundation     0x000000018356446c -[__NSDictionaryM objectForKey:] + 108 (NSDictionary.m:543) 
1 CoreFoundation     0x0000000183564450 -[__NSDictionaryM objectForKey:] + 80 (NSDictionary.m:538) 
2 Name Of May App     0x0000000100021f38 -[Model findAddress:] + 268 (Model.m:590) 
3 Name Of May App     0x00000001000beb78 _TTSf4g_n_n___TFC14Caller_Name_ID28BlockedNumbersViewController17formatBlockedCellfT6callerCS_6Caller3rowSi_CS_11BlockedCell + 1688 (BlockedNumbersViewController.swift:395) 
4 Name Of May App     0x00000001000bf1b0 _TTSf4g_g_n___TFC14Caller_Name_ID28BlockedNumbersViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 528 (BlockedNumbersViewController.swift:0) 
5 Name Of May App     0x00000001000ba01c _TToFC14Caller_Name_ID28BlockedNumbersViewController9tableViewfTCSo11UITableView12cellForRowAtV10Foundation9IndexPath_CSo15UITableViewCell + 76 (BlockedNumbersViewController.swift:0) 
6 UIKit       0x0000000189af5aa8 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 688 (UITableView.m:10803) 
7 UIKit       0x0000000189af5cc0 -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 80 (UITableView.m:10848) 
8 UIKit       0x0000000189ae33c4 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2152 (UITableView.m:2273) 
9 UIKit       0x0000000189afacb0 -[UITableView _performWithCachedTraitCollection:] + 120 (UITableView.m:12556) 
10 UIKit       0x0000000189893774 -[UITableView layoutSubviews] + 176 (UITableView.m:7390) 
11 UIKit       0x00000001897adf98 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1200 (UIView.m:14232) 
12 QuartzCore      0x000000018699e274 -[CALayer layoutSublayers] + 148 (CALayer.mm:8937) 
13 QuartzCore      0x0000000186992de8 CA::Layer::layout_if_needed(CA::Transaction*) + 292 (CALayer.mm:8817) 
14 QuartzCore      0x0000000186992ca8 CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 32 (CALayer.mm:2345) 
15 QuartzCore      0x000000018690e34c CA::Context::commit_transaction(CA::Transaction*) + 252 (CAContextInternal.mm:1689) 
16 QuartzCore      0x00000001869353ac CA::Transaction::commit() + 504 (CATransactionInternal.mm:420) 
17 QuartzCore      0x0000000186935e78 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 120 (CATransactionInternal.mm:793) 
18 CoreFoundation     0x000000018362c9a8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32 (CFRunLoop.c:1802) 
19 CoreFoundation     0x000000018362a630 __CFRunLoopDoObservers + 372 (CFRunLoop.c:1898) 
20 CoreFoundation     0x000000018362aa7c __CFRunLoopRun + 956 (CFRunLoop.c:2849) 
21 CoreFoundation     0x000000018355ada4 CFRunLoopRunSpecific + 424 (CFRunLoop.c:3113) 
22 GraphicsServices    0x0000000184fc5074 GSEventRunModal + 100 (GSEvent.c:2245) 
23 UIKit       0x0000000189815f74 UIApplicationMain + 208 (UIApplication.m:4089) 
24 Name Of May App     0x000000010003a8b4 main + 56 (Database.swift:17) 
25 libdyld.dylib     0x000000018256959c start + 4 
+0

我想和一個併發調用的問題......在'-init'中做一個異步調用,我不認爲這是建議的。相反,我會在'findAddress'上創建一個塊,並且像我們在UITableView中加載圖像一樣。 – Larme

+0

在init中啓動異步進程不是問題;它經常用於昂貴的初始化過程。但是,您確定這很可能是併發問題。 – bbum

回答

0

可變字典不是線程安全的。

您需要確保字典只能從單個線程訪問。

請注意dispatch_asyncinit不是問題。但在這種情況下不太可能需要。您是否測量了readCityAndStates方法的執行時間,以確定它是否確實是性能問題?另外,不要將該靜態資源存儲爲JSON,而應將其存儲爲二進制格式。這將解析得更快,而且更重要的是,可以縮減應用程序包的大小。

+0

字典可能需要2或3秒才能填充。確保只能從單個線程訪問的最佳方式是什麼? – Gruntcakes

+0

首先,轉向使用二進制存儲格式。 NSArchiver應該做的伎倆。我敢打賭,這將足夠快。接下來,該字典應該只填充一次,因爲根據定義,應用程序主包中的資源不能更改。如果二進制格式的速度不夠快,那麼只有這樣,才能考慮如何使線程安全。 – bbum