iOS卡顿监测

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/piratest/article/details/85012228

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

 

 

展开阅读全文

没有更多推荐了,返回首页