1、野指针问题

【EXC_BAD_ACCESS (SIGSEGV) / KERN_INVALID_ADDRESS]

Possible zombie in call: Function: objc_releaseParam 1: 0x157f2a740 Originated at or in a subcall of unknown, cannot find symb

如有以下崩溃栈可以怀疑是在dealloc中直接或间接使用了@try{} @catch{}

2、崩溃栈

  libobjc.A.dylib    _objc_release()         
  CoreFoundation     -[__NSDictionaryI dealloc]()         
  CoreFoundation     -[NSException dealloc]()         
  libobjc.A.dylib    AutoreleasePoolPage::releaseUntil(objc_object**)()         
  libobjc.A.dylib    _objc_autoreleasePoolPop()        
   ......
   ......

3、场景复现代码

#import "ViewController.h"
@interface TestExpectionObj : NSObject
@end
@implementation TestExpectionObj
- (void)dealloc {
    @try {
        [self setValue:@"test" forKey:@"testKey"];
    } @catch (NSException *exception) {
        NSLog(@"%@", exception);
    }
}
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [TestExpectionObj new];
}
@end

4、问题分析

dealloc使用try-catch并触发catch时,会生成NSException对象,exception结构如下

exception : NSException {
	userInfo: NSDictionary {
		NSTargetObjectUserInfoKey = "<TestExpectionObj: 0x6000038ac3e0>";
	}
}

exception会强引用TestExpectionObj对象,并且exception一般都是类方法生成会自动加入到AutoreleasePool,所以dealloc执行完后TestExpectionObj对象已经释放(因为在dealloc方法中在强引用当前对象没法终止当前对象的释放,引用计数增加与否已无意义),所以exception.userInfo中的TestExpectionObj对变成野对象。

AutoreleasePool到达周期释放时就对调用release exception & userInfo,字典userInfo释放时会也会相应的释放key/value,故NSTargetObjectUserInfoKey = "<TestExpectionObj: 0x6000038ac3e0>"又调用一次release,因为之前已经dealloc完毕,所以这次就会触发重复释放崩溃引起野指针问题,

但如果exceptionTestExpectionObj对象的dealloc方法执行完之前释放就不会出现问题。

5、上报可能引起野指针崩溃栈

#import <JRSwizzle/JRSwizzle.h>
@implementation NSException (ExceptionTestSunztObj)
  (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [self jr_swizzleMethod:NSSelectorFromString(@"dealloc")
                              withMethod:@selector(intercept_dealloc)
                                   error:nil];
    });
}
- (void)intercept_dealloc {
    BOOL isContainDealloc = NO;
    NSMutableString *symblos = [NSMutableString string];
    for (NSString *sym in self.callStackSymbols) {
        [symblos appendFormat:@"%@\n", sym];
        if ([sym containsString:@" dealloc]"]) {
            isContainDealloc = YES;
        }
    }
    // 把 symblos上报给自己的APM平台
    [APM report:@"ttReportExceptionCallStackSymbols" withValue:symblos];
    [APM report:@"ttReportExceptionReason" withValue:self.reason?:@"NULL"];
    if (isContainDealloc) {
        // 本地log打印,需符号化
       TTLocalLog("NSException:throws:dealloc:ttReport", {
           @"name": self.name?:@"",
           @"reason": self.reason?:@"",
           @"callStackSymbols": symblos
       });
       // 延迟保证数据写完在释放
       __unsafe_unretained NSException *demoSelf = self;
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
           [demoSelf intercept_dealloc];
       });
       return;
    }
    [self intercept_dealloc];
}
@end

注:在dealloc中使用@try{} @catch{}可能会引起难以排查的野指针崩溃

使用@try-@catch

[<TestExpectionObj 0x600000714220> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key testKey.
(
  0   CoreFoundation                      0x0000000102a93604 __exceptionPreprocess   242
  1   libobjc.A.dylib                     0x0000000102943a45 objc_exception_throw   48
  2   CoreFoundation                      0x0000000102a9329c -[NSException init]   0
  3   Foundation                          0x00000001034f2354 -[NSObject(NSKeyValueCoding) setValue:forKey:]   315
  4   ExpectionDemo                       0x00000001023cae52 -[TestExpectionObj dealloc]   50
  5   libobjc.A.dylib                     0x00000001029417b7 _ZN11objc_object17sidetable_releaseEbb   177
  6   ExpectionDemo                       0x00000001023caf58 -[ViewController viewDidLoad]   72
  7   UIKitCore                           0x000000010f3ce3bc -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled]   88
  8   UIKitCore                           0x000000010f3d2dbf -[UIViewController loadViewIfRequired]   1193
  9   UIKitCore                           0x000000010f3d319a -[UIViewController view]   27
  10  UIKitCore                           0x000000010fbdb00a -[UIWindow addRootViewControllerViewIfPossible]   305
  11  UIKitCore                           0x000000010fbda6fe -[UIWindow _updateLayerOrderingAndSetLayerHidden:actionBlock:]   230
  12  UIKitCore                           0x000000010fbdb6d6 -[UIWindow _setHidden:forced:]   409
  13  UIKitCore                           0x000000010fbee204 -[UIWindow _mainQueue_makeKeyAndVisible]   47
  14  UIKitCore                           0x000000010fe605f6 -[UIWindowScene _makeKeyAndVisibleIfNeeded]   202
  15  UIKitCore                           0x000000010ef0fb8f  [UIScene _sceneForFBSScene:create:withSession:connectionOptions:]   1591
  16  UIKitCore                           0x000000010fb98fbd -[UIApplication _connectUISceneFromFBSScene:transitionContext:]   1299
  17  UIKitCore                           0x000000010fb99471 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:]   301
  18  UIKitCore                           0x000000010f613afe -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:]   355
  19  FrontBoardServices                  0x0000000107090cdd -[FBSScene _callOutQueue_agent_didCreateWithTransitionContext:completion:]   415
  20  FrontBoardServices                  0x00000001070bd216 __94-[FBSWorkspaceScenesClient createWithSceneID:groupID:parameters:transitionContext:completion:]_block_invoke.180   102
  21  FrontBoardServices                  0x000000010709f0ef -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]   209
  22  FrontBoardServices                  0x00000001070bcdf5 __94-[FBSWorkspaceScenesClient createWithSceneID:groupID:parameters:transitionContext:completion:]_block_invoke   352
  23  libdispatch.dylib                   0x0000000103c0ba5b _dispatch_client_callout   8
  24  libdispatch.dylib                   0x0000000103c0e93b _dispatch_block_invoke_direct   295
  25  FrontBoardServices                  0x00000001070e3da3 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__   30
  26  FrontBoardServices                  0x00000001070e3c99 -[FBSSerialQueue _targetQueue_performNextIfPossible]   174
  27  FrontBoardServices                  0x00000001070e3dcb -[FBSSerialQueue _performNextFromRunLoopSource]   19
  28  CoreFoundation                      0x0000000102a004a7 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__   17
  29  CoreFoundation                      0x0000000102a0039f __CFRunLoopDoSource0   180
  30  CoreFoundation                      0x00000001029ff8ce __CFRunLoopDoSources0   340
  31  CoreFoundation                      0x00000001029f9f68 __CFRunLoopRun   871
  32  CoreFoundation                      0x00000001029f9704 CFRunLoopRunSpecific   562
  33  GraphicsServices                    0x00000001071e3c8e GSEventRunModal   139
  34  UIKitCore                           0x000000010fb9765a -[UIApplication _run]   928
  35  UIKitCore                           0x000000010fb9c2b5 UIApplicationMain   101
  36  ExpectionDemo                       0x00000001023cb1be main   110
  37  dyld                                0x00000001025e6f21 start_sim   10
  38  ???                                 0x00000001091ce4fe 0x0   4447855870
)

这种崩溃信息使用NSSetUncaughtExceptionHandler()是抓不到的

以上就是ios开发 try-catch引起的野指针问题排查的详细内容,更多关于ios开发try-catch野指针的资料请关注Devmax其它相关文章!

ios开发 try-catch引起的野指针问题排查的更多相关文章

  1. PHP中Session的概念

    需要注意的是,一个Session的概念需要包括特定的客户端,特定的服务器端以及不中断的操作时间。例如,用户在负责登录的PHP脚本中设置了$user="wind",却无法在另一个PHP脚本中通过调用$user来获得“wind”这个值。Session解决方案,就是要提供在PHP脚本中定义全局变量的方法,使得这个全局变量在同一个Session中对于所有的PHP脚本都有效。那么在A用户所访问的PHP脚本中,$user的值就是wind。

  2. 多php服务器实现多session并发运行

    由于session的采用,大大方便了web开发员的工作。现在php4也加入session的支持,再度显示出opensource的强大力量。原来设计的静态的唯一的sessionID导致数据混乱。这样,动态生成一个唯一的sessionID成为当务之急。解决办法很简单:我用了php文件名时间戳为唯一的sessionID,这样在我的程序中的每个session就各就各位,不再混乱了。Mysessionname也不能用cookie方式存放,因为多个session肯定会覆盖掉原先的cookie文件。

  3. 关于Spring Boot内存泄露排查的记录

    这篇文章主要介绍了关于Spring Boot内存泄露排查的记录,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  4. 一个查看session内容的函数

    这篇文章主要给大家介绍了一个查看session内容的函数,需要的朋友可以参考下

  5. 在PHP3中实现SESSION的功能(三)

    phpsession_checkid;//20分钟后session失效//下面你需要设置mysql的连接参数mysql_connectorDie("can'tconnecttodb!session_write()){print$sess_error;}else{echo"session[username]被设置成:$session[username]";echo"session[userpass]被设置成:$session[userpass]";echo"

  6. Java NIO与IO的区别以及比较

    这篇文章主要介绍了Java NIO与IO的区别以及比较,文章通过围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

  7. session 的生命周期是多长

    1浏览器结束时其生命周期也同时结束,但是档案仍然存在于/tmp/(sess_???)2下次重新开浏览器时会重新分配sessionID,如果你使用session_id()把以前的ID带回来,则会去读取残存在/tmp处的sess_???

  8. 在PHP3中实现SESSION的功能(二)

    isset){$__cookie_inc__=1;functionJsSetCookie{//这个函数允许你在HTML头标记之后设置cookie,//可以作SetCookie函数的补充,甚至代替。

  9. 使用数据库保存session的方法

    php的session默认是以文件方式保存在服务器端,并且在客户端使用cookie保存变量,这就会出现一个问题,当一个用户由于某种安全原因关闭了浏览器的cookie,程序中的session相关操作将无法执行。因此,如果能以数据库保存session数据,将不受客户端设置的限制,并且在性能和扩展性等方面有一个飞跃。程序中使用关键函数是session_set_save_handler,同时要将php.ini里的session.save_handler=files改为user。>完成以上步骤后,在程序中使用req

  10. 在PHP3中实现SESSION的功能(一)

    //不过一般建议就使用session作为表名$sess_db='dbname';$sess_table='session';#----------------------------------------------------#Session_CheckID-检查、设置并返回Session-ID#参数......:cookie保存时间#也可不设置表示这个cookie只在当前session有效#这其实就象ASP中SESSION的时效一样。#返回值....:一个唯一的Session-ID#--------

随机推荐

  1. iOS实现拖拽View跟随手指浮动效果

    这篇文章主要为大家详细介绍了iOS实现拖拽View跟随手指浮动,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. iOS – genstrings:无法连接到输出目录en.lproj

    使用我桌面上的项目文件夹,我启动终端输入:cd然后将我的项目文件夹拖到终端,它给了我路径.然后我将这行代码粘贴到终端中找.-name*.m|xargsgenstrings-oen.lproj我在终端中收到此错误消息:genstrings:无法连接到输出目录en.lproj它多次打印这行,然后说我的项目是一个目录的路径?没有.strings文件.对我做错了什么的想法?

  3. iOS 7 UIButtonBarItem图像没有色调

    如何确保按钮图标采用全局色调?解决方法只是想将其转换为根注释,以便为“回答”复选标记提供更好的上下文,并提供更好的格式.我能想出这个!

  4. ios – 在自定义相机层的AVFoundation中自动对焦和自动曝光

    为AVFoundation定制图层相机创建精确的自动对焦和曝光的最佳方法是什么?

  5. ios – Xcode找不到Alamofire,错误:没有这样的模块’Alamofire’

    我正在尝试按照github(https://github.com/Alamofire/Alamofire#cocoapods)指令将Alamofire包含在我的Swift项目中.我创建了一个新项目,导航到项目目录并运行此命令sudogeminstallcocoapods.然后我面临以下错误:搜索后我设法通过运行此命令安装cocoapodssudogeminstall-n/usr/local/bin

  6. ios – 在没有iPhone6s或更新的情况下测试ARKit

    我在决定下载Xcode9之前.我想玩新的框架–ARKit.我知道要用ARKit运行app我需要一个带有A9芯片或更新版本的设备.不幸的是我有一个较旧的.我的问题是已经下载了新Xcode的人.在我的情况下有可能运行ARKit应用程序吗?那个或其他任何模拟器?任何想法或我将不得不购买新设备?解决方法任何iOS11设备都可以使用ARKit,但是具有高质量AR体验的全球跟踪功能需要使用A9或更高版本处理器的设备.使用iOS11测试版更新您的设备是必要的.

  7. 将iOS应用移植到Android

    我们制作了一个具有2000个目标c类的退出大型iOS应用程序.我想知道有一个最佳实践指南将其移植到Android?此外,由于我们的应用程序大量使用UINavigation和UIView控制器,我想知道在Android上有类似的模型和实现.谢谢到目前为止,guenter解决方法老实说,我认为你正在计划的只是制作难以维护的糟糕代码.我意识到这听起来像很多工作,但从长远来看它会更容易,我只是将应用程序的概念“移植”到android并从头开始编写.

  8. ios – 在Swift中覆盖Objective C类方法

    我是Swift的初学者,我正在尝试在Swift项目中使用JSONModel.我想从JSONModel覆盖方法keyMapper,但我没有找到如何覆盖模型类中的Objective-C类方法.该方法的签名是:我怎样才能做到这一点?解决方法您可以像覆盖实例方法一样执行此操作,但使用class关键字除外:

  9. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  10. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

返回
顶部