廢話不多說(shuō)账月,直奔主題综膀。不想看過(guò)程的也可以直接劃到底部看總結(jié)。
這兩天新拿到一份代碼局齿,在上報(bào)發(fā)布的模塊頁(yè)面剧劝,編輯相冊(cè)圖片(添加多行水印)的時(shí)候抓歼,程序內(nèi)存峰值直接飆升到四百多兆讥此。身邊的同事告訴我,是因?yàn)檎{(diào)用下圖所示的封裝方法導(dǎo)致的谣妻,希望我能來(lái)優(yōu)化一下萄喳。
//1.開(kāi)啟上下文
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0);
//2.繪制圖片
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//添加水印文字
[text drawAtPoint:point withAttributes:attributed];
//3.從上下文中獲取新圖片
UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
//4.關(guān)閉圖形上下文
UIGraphicsEndImageContext();
//返回圖片
return newImage;
我運(yùn)行程序看一下這個(gè)功能模塊,內(nèi)存確實(shí)直接飆到了四百多M蹋半。
于是就按照同事講的先試著從這個(gè)方法入手他巨。
首先想到的是使用 autoreleasepool,因?yàn)榻o圖片添加多行水印是通過(guò)循環(huán)添加的减江,所以我想使用自動(dòng)釋放池就可以在循環(huán)結(jié)束后釋放內(nèi)存染突。結(jié)果無(wú)效,內(nèi)存無(wú)法被回收辈灼。然后我開(kāi)始測(cè)試具體是哪句代碼導(dǎo)致內(nèi)存瘋長(zhǎng)份企,經(jīng)過(guò)排除,最終定位是由于繪制UIImage的drawInRect方法巡莹。之后就開(kāi)始想有沒(méi)有什么好的方法替代她司志,經(jīng)過(guò)查看了一些相冊(cè)開(kāi)源庫(kù)發(fā)現(xiàn)很多也都是直接用這句代碼來(lái)處理圖片,于是就放棄了榕莺。最后開(kāi)始來(lái)看項(xiàng)目中該模塊的代碼,看能不能從代碼邏輯上進(jìn)行優(yōu)化處理(代碼比較老棵介,整個(gè)功能模塊的代碼行數(shù)達(dá)到兩千多行)钉鸯。經(jīng)過(guò)對(duì)照功能需求反復(fù)查看原代碼,發(fā)現(xiàn)了添加水印的時(shí)候邮辽,因?yàn)橐笳故径嘈形淖诌氲瘢悦刻砑右淮嗡《贾匦吕L制了一次圖片。于是我認(rèn)為可以從這里作為切入點(diǎn)進(jìn)行優(yōu)化吨述,我把多行文字統(tǒng)一處理岩睁,將多次圖片處理合并成一次,最終內(nèi)存峰值由四百多兆降到了一百多兆揣云,性能提高了70%捕儒。效果如下圖所示:
【總結(jié)思路】使用drawInRect繪制圖片,每繪畫(huà)生成一次新圖就漲一次內(nèi)存,連續(xù)多次繪制就會(huì)導(dǎo)致內(nèi)存飆升刘莹。這個(gè)時(shí)候只需要將多次處理盡量合并成一次處理即可阎毅。