【问题标题】:EXC_BAD_ACCESS KERN_INVALID_ADDRESS but memory is not being deletedEXC_BAD_ACCESS KERN_INVALID_ADDRESS 但内存没有被删除
【发布时间】:2017-07-24 16:24:00
【问题描述】:

我在已发布的应用程序中偶尔发生崩溃,并且从崩溃报告中知道它发生的行和崩溃类型 - EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS - 但我不知道内存如何因为生命周期而变得无效被引用的对象的生命周期是应用程序的生命周期,除非应用程序终止,否则不会被删除。因此,如果崩溃不是由于访问已删除的内存(因为该内存没有被删除)在这种特殊情况下 EXC_BAD_ACCESS 可能还有什么其他原因?

代码如下:

 @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 将为 nil,因此在 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

【问题讨论】:

  • 我会处理并发调用的问题...在-init 中进行异步调用,我认为不建议这样做。我会改为在 findAddress 上创建一个块,并执行与在 UITableView 中加载图像相同的操作。
  • 在init 中启动异步进程不是问题;它通常用于昂贵的初始化过程。但是,您说得对,这很可能是并发问题。

标签: ios objective-c


【解决方案1】:

可变字典不是线程安全的。

您需要确保字典只能从单个线程访问。

请注意,init 中的 dispatch_async 不是问题。但在这种情况下,它不太可能是必要的。您是否测量了 readCityAndStates 方法的执行时间以确定它是否真的是性能问题?同样,您应该将其存储为二进制格式,而不是将该静态资源存储为 JSON。这将大大加快解析速度,更重要的是,会减少应用程序包的大小。

【讨论】:

  • 字典填充可能需要 2 或 3 秒。确保仅从单个线程访问它的最佳方法是什么?
  • 首先,转而使用二进制存储格式。 NSArchiver 应该可以解决问题。我打赌那会足够快。接下来,该字典应该只填充一次,因为根据定义,来自应用程序主包的资源不能更改。如果二进制格式不够快,那么只有到那时,您才应该考虑如何使其成为线程安全的。
猜你喜欢
  • 1970-01-01
  • 2012-10-09
  • 2017-04-02
  • 2020-04-13
  • 2023-03-23
  • 1970-01-01
  • 2016-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多