野指针扑获实战篇

一、背景

上一篇我们知道如何通过xcode工具去探测出野指针问题,但是面临两个重大弊端

  • 测试同学无法直接使用
  • 人工debug测试,对于一些释放后再次使用的对象来说测试周期短还是无法获取

针对以上两个痛点,我们需要开发一款工具,嵌入我们的工程使随时随地可以进行野指针case扑获

二、检测原理

  • 当对象调用dealloc时,仅解除对象的引用关系,然后将该对象变为僵尸对象,同时添加NSProxy协议用于接受消息进行消息转发打印异常信息
  • 通过链表管理僵尸对象,对象包含指针p,原对象以及加入时间。
  • 当僵尸对象在30秒以内被再次访问时,就会通过NSProxy转发原对象,调用方法,以及堆栈信息,抛给业务层,由业务层自行处理。
  • 定时扫描僵尸对象,存留超过30秒的僵尸对象,将被清理,回收内存。

三、目标

  • 拦截野指针防止crash
  • 拦截野指针对战进行上报

四、方案评估

本篇方案:

这篇文章采用拦截dealloc构造zombie对象进行消息转发获取给已释放对象发消息的堆栈

原因

不管是使用hook c层的free方法还是上层oc对象的dealloc方法,实际底层都是特别消耗性能的,两者相比hook c层的free方法,覆盖面表广,消耗性能也多,所以综合我们的实际情况选择后者

五、具体实现

核心主要流程

外部使用工具

引入pod库

js 复制代码
pod 'HuntingZombiesTool'

初始化配置

js 复制代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    
    //当检测到野指针后的回调,由业务自行处理。可选择上报错误,也可以直接crash
    ZombieConfig.share.throwInfo = ^(NSString * _Nonnull info) {
        @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:info userInfo:nil];
    };
    
    //司机侧示例代码
    ZombieConfig.share.throwInfo = ^(NSString * _Nonnull info) {
        NSLog(info);
        //可以上报到自己分析平台
    };
    ZombieConfig.share.zombieActivityTime = 30;
    ZombieConfig.share.classes = [self ownClassesInfo];//如果这里传空,默认是扫描所有类
    [ZombieConfig.share startZombie];
    
    return YES;
}

//获取本项目非系统库的类
- (NSArray <Class>*)ownClassesInfo {
    NSMutableArray *resultArray = [NSMutableArray array];
    unsigned int classCount;
    const char **classes;
    Dl_info info;
    dladdr(&_mh_execute_header, &info);
    classes = objc_copyClassNamesForImage(info.dli_fname, &classCount);

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_apply(classCount, dispatch_get_global_queue(0, 0), ^(size_t iteration) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSString *className = [NSString stringWithCString:classes[iteration] encoding:NSUTF8StringEncoding];
        Class class = NSClassFromString(className);
        [resultArray addObject:class];
        dispatch_semaphore_signal(semaphore);
    });
    return resultArray.mutableCopy;
}

测试类

js 复制代码
# 该类设置mrc

- (void)tmpBtnClickd:(UIButton *)sender {
    UIView* testObj = [[UIView alloc] init];
    [testObj release];
    [testObj setNeedsLayout];
}

效果

六、依赖信息

野指针扑获pod库及demo

到这里就完毕了,感谢您的阅读,欢迎阅读我的其他文章!

相关推荐
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
点金石游戏出海16 小时前
每周资讯 | Krafton斥资750亿日元收购日本动画公司ADK;《崩坏:星穹铁道》新版本首日登顶iOS畅销榜
游戏·ios·业界资讯·apple·崩坏星穹铁道
旷世奇才李先生18 小时前
Swift 安装使用教程
开发语言·ios·swift
90后的晨仔18 小时前
Xcode16报错: SDK does not contain 'libarclite' at the path '/Applicati
ios
finger2448019 小时前
谈一谈iOS线程管理
ios·objective-c
Digitally19 小时前
如何将大型视频文件从 iPhone 传输到 PC
ios·iphone
梅名智20 小时前
IOS 蓝牙连接
macos·ios·cocoa
美狐美颜sdk1 天前
跨平台直播美颜SDK集成实录:Android/iOS如何适配贴纸功能
android·人工智能·ios·架构·音视频·美颜sdk·第三方美颜sdk
恋猫de小郭1 天前
Meta 宣布加入 Kotlin 基金会,将为 Kotlin 和 Android 生态提供全新支持
android·开发语言·ios·kotlin
泓博1 天前
Objective-c把字符解析成字典
开发语言·ios·objective-c