iOS卡顿监测

App在线运行的时候发生了卡顿,是很难了解卡顿原因的。

一个相对比较有用的办法是做一个常驻线程,定时抓取主线程的运行时状态,当主线程的运行时状态在几个周期里总是处于同一个状态/或同一类状态时,则大概率认为发生了卡顿,此时使用CrashReporter这个第三方组件模拟一个crash获取到对应的call stack就好对问题进行跟进了。

至于程序员怎么拿到call stack进行分析,则各有各的办法,有些会自己搭建一个后台服务,将call stack信息做上传,我们就不想搞那么多东西,直接上传到Bugfender了,实时查看。

代码内容是参考了一些blog之后写的,具体的文章确实已经记不起了,以下将我用到的代码写下,以做为备忘。

#import <Foundation/Foundation.h>

@interface PerformanceMonitor : NSObject

+ (instancetype)sharedInstance;

- (void)start;
- (void)stop;

@end

 

#import "PerformanceMonitor.h"
#import <CrashReporter/CrashReporter.h>
#import "DDFileLogger.h"

static int kTimeout = 1000;//单次定时器触发时间,1000毫秒
static int kTimeoutCount = 3;//定时器触发次数,总时间为timeout * timeoutCount

@interface PerformanceMonitor ()

@property (nonatomic, assign) int timeoutCount;
@property (nonatomic, assign) CFRunLoopObserverRef observer;
@property (nonatomic, strong) dispatch_semaphore_t semaphore;
@property (nonatomic, assign) CFRunLoopActivity activity;

@end

@implementation PerformanceMonitor

+ (instancetype)sharedInstance {
    static id instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) {
    PerformanceMonitor *moniotr = (__bridge PerformanceMonitor*)info;
    moniotr.activity = activity;
    dispatch_semaphore_t semaphore = moniotr.semaphore;
    dispatch_semaphore_signal(semaphore);
}

- (void)stop {
    if (!_observer)
        return;
    
    CFRunLoopRemoveObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
    CFRelease(_observer);
    _observer = NULL;
}

- (void)start {
    if (_observer)
        return;
    
    // 信号
    _semaphore = dispatch_semaphore_create(0);
    
    // 注册RunLoop状态观察
    CFRunLoopObserverContext context = {0,(__bridge void*)self,NULL,NULL};
    _observer = CFRunLoopObserverCreate(kCFAllocatorDefault,
                                        kCFRunLoopAllActivities,
                                        YES,
                                        0,
                                        &runLoopObserverCallBack,
                                        &context);
    CFRunLoopAddObserver(CFRunLoopGetMain(), _observer, kCFRunLoopCommonModes);
    
    WS(ws);
    
    // 在子线程监控时长
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (YES) {
            long st = dispatch_semaphore_wait(ws.semaphore, dispatch_time(DISPATCH_TIME_NOW, kTimeout*NSEC_PER_MSEC));
            if (st != 0) {
                if (!ws.observer) {
                    ws.timeoutCount = 0;
                    ws.semaphore = 0;
                    ws.activity = 0;
                    return;
                }
                
                if (ws.activity == kCFRunLoopBeforeSources || ws.activity == kCFRunLoopAfterWaiting) {
                    if (++ws.timeoutCount < kTimeoutCount)
                        continue;
                    
                    PLCrashReporterConfig *config = [[PLCrashReporterConfig alloc] initWithSignalHandlerType:PLCrashReporterSignalHandlerTypeBSD symbolicationStrategy:PLCrashReporterSymbolicationStrategyAll];
                    PLCrashReporter *crashReporter = [[PLCrashReporter alloc] initWithConfiguration:config];
                    
                    NSData *data = [crashReporter generateLiveReport];
                    PLCrashReport *reporter = [[PLCrashReport alloc] initWithData:data error:NULL];
                    NSString *report = [PLCrashReportTextFormatter stringValueForCrashReport:reporter withTextFormat:PLCrashReportTextFormatiOS];
                    
                    NSLog(@"------------\n%@\n------------", report);
                    NSString* uin = [UserDefaultHelper myUINString];
                    NSString* version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
                    NSString* build = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
                    NSString* title = [NSString stringWithFormat:@"%@_%@.%@",uin,version,build];
                    [Bugfender sendIssueWithTitle:title text:report];
                }
            }
            ws.timeoutCount = 0;
        }
    });
}

@end

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值