1挣菲、了解CPU與GPU
在屏幕成像的過程中,CPU和GPU起著至關(guān)重要的作用
CPU(Central Processing Unit,中央處理器)
對(duì)象的創(chuàng)建和銷毀彻况、對(duì)象屬性的調(diào)整、布局計(jì)算舅踪、文本的計(jì)算和排版纽甘、圖片的格式轉(zhuǎn)換和解碼、圖像的繪制(Core Graphics)
GPU(Graphics Processing Unit抽碌,圖形處理器)
處理紋理的渲染
在iOS中是雙緩沖機(jī)制悍赢,有前幀緩存、后幀緩存货徙;
屏幕成像原理:
卡頓產(chǎn)生的原因
按照60FPS的刷幀率左权,每隔16ms就會(huì)有一次VSync信號(hào),當(dāng)VSync信號(hào)到來時(shí)痴颊,GPU還沒完成渲染赏迟,便要等待到下一幀到來時(shí)才會(huì)顯示,這就照成了丟幀卡頓蠢棱。
2锌杀、優(yōu)化思路:
盡可能減少CPU、GPU資源消耗
CPU優(yōu)化思路點(diǎn):
1裳扯、盡量使用輕量級(jí)的對(duì)象抛丽,比如用不到事件處理的地方,可以考慮用CALayer取代UIView
2饰豺、不要頻繁地調(diào)用UIView的相關(guān)屬性亿鲜,比如frame、bound冤吨、transform等屬性蒿柳,盡量減少不必要的修改;
3漩蟆、盡量提前計(jì)算好布局垒探,在有需要時(shí)進(jìn)行一次性調(diào)整對(duì)應(yīng)的屬性,不要多次修改屬性怠李;
4圾叼、autolayout會(huì)比直接設(shè)置frame消耗更多的CPU資源蛤克;
5、圖片的size最好和uiview的size保持一致夷蚊;
6构挤、控制下線程的最大并發(fā)量;
7惕鼓、盡量把耗時(shí)的操作放到子線程處理筋现,如文本處理,尺寸計(jì)算箱歧、繪制矾飞;圖片的解碼
樣例性能對(duì)比(圖片解碼)
直接給視圖添加imageView,并設(shè)置圖片
UIImageView *imageView = [[UIImageView alloc] init];
imageView.frame=CGRectMake(100,100,100,56);
[self.view addSubview:imageView];
?self.imageView= imageView;
?self.imageView.image = [UIImage imageNamed:@"timg"];
性能檢測
同樣是給視圖添加imageView呀邢,并設(shè)置圖片
? ? UIImageView *imageView = [[UIImageView alloc] init];
? ? imageView.frame=CGRectMake(100,100,100,56);
[self.viewaddSubview:imageView];
?self.imageView= imageView;
? ? dispatch_async(dispatch_get_global_queue(0, 0), ^{
? ? ? ? // 獲取CGImage
? ? ? ? CGImageRefcgImage = [UIImageimageNamed:@"timg"].CGImage;
? ? ? ? // alphaInfo
? ? ? ? CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgImage) & kCGBitmapAlphaInfoMask;
?BOOLhasAlpha =NO;
?if?(alphaInfo == kCGImageAlphaPremultipliedLast ||
? ? ? ? ? ? alphaInfo ==kCGImageAlphaPremultipliedFirst ||
? ? ? ? ? ? alphaInfo ==kCGImageAlphaLast||
? ? ? ? ? ? alphaInfo ==kCGImageAlphaFirst) {
hasAlpha =YES;
? ? ? ? }
? ? ? ? // bitmapInfo
? ? ? ? CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
? ? ? ? bitmapInfo |= hasAlpha ?kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
? ? ? ? // size
? ? ? ? size_twidth =CGImageGetWidth(cgImage);
? ? ? ? size_theight =CGImageGetHeight(cgImage);
? ? ? ? // context
CGContextRefcontext =CGBitmapContextCreate(NULL, width, height,8,0,CGColorSpaceCreateDeviceRGB(), bitmapInfo);
? ? ? ? // draw
? ? ? ? CGContextDrawImage(context,CGRectMake(0,0, width, height), cgImage);
? ? ? ? // get CGImage
? ? ? ? cgImage =CGBitmapContextCreateImage(context);
? ? ? ? // into UIImage
? ? ? ? UIImage*newImage = [UIImageimageWithCGImage:cgImage];
? ? ? ? // release
? ? ? ? CGContextRelease(context);
? ? ? ? CGImageRelease(cgImage);
? ? ? ? // back to the main thread
? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
?self.imageView.image= newImage;
? ? ? ? });
? ? });
性能檢測
文本的子線程計(jì)算異步洒沦,主線程渲染
// 文字計(jì)算
[@"text" boundingRectWithSize:CGSizeMake(100, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];? ??
// 文字繪制? ?
[@"text" drawWithRect:CGRectMake(0, 0, 100, 100) options:NSStringDrawingUsesLineFragmentOrigin attributes:nil context:nil];
GPU優(yōu)化思路:
1、盡量避免短時(shí)間內(nèi)大量圖片的顯示驼鹅,盡可能將多張圖片合成一張進(jìn)行顯示微谓;
2、GPU能處理的最大紋理尺寸是4096x4096输钩,一旦超過這個(gè)尺寸,就會(huì)占用CPU資源進(jìn)行處理仲智,所以紋理盡量不要超過這個(gè)尺寸买乃;
3、盡量減少視圖數(shù)量和層次钓辆;
4剪验、減少透明的視圖(alpha<1),不透明的就設(shè)置opaque為YES
5前联、盡量避免出現(xiàn)離屏渲染
3功戚、離屏渲染
在openGL中,GPU有兩種渲染方式
On-screen rendering: 當(dāng)前屏幕渲染似嗤,在當(dāng)前用于顯示屏幕緩沖區(qū)進(jìn)行渲染操作啸臀;(默認(rèn)方式)
Off-screen rendering: 離屏渲染,在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染烁落。
離屏渲染比較消耗性能原因:
需要?jiǎng)?chuàng)建緩沖區(qū)乘粒;
整個(gè)過程需要多次切換上下文環(huán)境,先是從當(dāng)前屏幕切換到離屏伤塌,渲染結(jié)束后將離屏渲染區(qū)的渲染結(jié)果繪制到當(dāng)前屏幕灯萍,又需要切換上下文環(huán)境
離屏渲染觸發(fā):
光柵化,layer.shouldRasterize = YES
遮罩每聪,layer.mask
圓角旦棉,同時(shí)設(shè)置layer.masksToBounds = YES齿风、layer.cornerRadius大于0
考慮通過CoreGraphics繪制裁剪圓角,或者叫美工提供圓角圖片
陰影绑洛,layer.shadowXXX 救斑,如果設(shè)置了layer.shadowPath就不會(huì)產(chǎn)生離屏渲染。
4诊笤、卡頓檢測
“卡頓”主要是因?yàn)樵谥骶€程執(zhí)行了比較耗時(shí)的操作
可以添加Observer到主線程RunLoop中系谐,通過監(jiān)聽RunLoop狀態(tài)切換的耗時(shí),以達(dá)到監(jiān)控卡頓的目的