




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
深入剖析IOS性能優(yōu)化技術(shù)創(chuàng)新,變革未來(lái)什么影晌性能?女可僉則?時(shí)間復(fù)雜度數(shù)組O(n)
會(huì)遍歷的接口:containsObject:,indexOfObject*,removeObject:O(1)
棧頂棧底操作:objectAtIndex:,firstObject:,lastObject:,addObject:,removeLastObject:O(logn)二分查找:indexOfObject:inSortedRange:options:usingComparator:Dictionary和
Set無(wú)序沒(méi)有重復(fù)元素,通過(guò)
hash
table
進(jìn)行快速的操作添加刪除和查找都是
O(1)
的containsObject不同實(shí)現(xiàn)containsObject
in
數(shù)組-(BOOL)containsObject:
(id)anObject{return([selfindexOfObject:anObject]!=
NSNotFound);}-(NSUInteger)indexOfObject:
(id)anObject{unsigned c=[self
count];if(c>0&&anObject!=
nil){unsigned i;IMPget=[selfmethodForSelector:
oaiSel];BOOL (*eq)(id,SEL,id)=(BOOL(*)(id,SEL,id))[anObjectmethodForSelector:
eqSel];for(i=0;i<c;
i++)if((*eq)(anObject,eqSel,(*get)(self,oaiSel,i))==
YES)return
i;}return
NSNotFound;}containsObjectin
Set-(BOOL)containsObject:
(id)anObject{return(([selfmember:anObject])?YES:
NO);}-(id)member:
(id)anObject{if(anObject!=
nil){GSIMapNodenode=GSIMapNodeForKey(&map,
(GSIMapKey)anObject);if(node!=
0){return
node->key.obj;}}return
nil;}GCD通過(guò)
dispatch_block_create_with_qos_class
方法指定隊(duì)列的QoS
為
QOS_CLASS_UTILITY(>=
iOS
8)。這個(gè)
QoS
系統(tǒng)會(huì)針對(duì)大的計(jì)算,I/O,網(wǎng)絡(luò)以及復(fù)雜數(shù)據(jù)處理做電量?jī)?yōu)化。/\、-一睿爆炸和死鎖//線(xiàn)程爆炸for(inti=0;i<999;i++){dispatch_async(q,
^{...});}//會(huì)造成死鎖dispatch_barrier_sync(q,^{});避免方式—使用串行隊(duì)列
NSOperationQueuesNSOperationQueue.maxConcurrentOperationCount
dispatch_apply(999,q,^(size_t
i){...});四#defineCONCURRENT_TASKS
4sema=
dispatch_semaphore_create(CONCURRENT_TASKS);for(inti=0;i<999;
i++){dispatch_async(q,
^{dispatch_semaphore_signal(sema);});dispatch_semaphore_wait(sema,
DISPATCH_TIME_FOREVER);}I/O將零碎的內(nèi)容作為—個(gè)整體進(jìn)行寫(xiě)入使用合適的
I/O
操作
API使用合適的線(xiàn)程使用
NSCache
做緩存能夠減少
I/O-l
UO勺為什么不直接用字典?自動(dòng)清理系統(tǒng)占用內(nèi)存NSCache
是線(xiàn)程安全-(void)cache:(NSCache
*)cachewillEvictObject:(id)obj; 緩存對(duì)象將被清理時(shí)的回調(diào)evictsObjectsWithDiscardedContent
可以控制是否清理NSCache
里有個(gè)NSMutableDictionary@implementation
NSCache-(id)
init{if(nil==(self=[super
init])){return
nil;}_objects=[NSMutableDictionary
new];_accesses=[NSMutableArray
new];return
self;}還有些額外信息@interface_GSCachedObject:NSObject{@publicid
object;
//cache
的值NSString
*key;
//設(shè)置
cache
的
keyint
accessCount;
//保存訪(fǎng)問(wèn)次數(shù),用于自動(dòng)清理NSUIntegercost;//setObject:forKey:cost:BOOL
isEvictable;
//線(xiàn)程安全}@endCache
讀取-(id)objectForKey:
(id)key{_GSCachedObject*obj=[_objectsobjectForKey:
key];if(nil==
obj){return
nil;}if
(obj->isEvictable)
//保證添加刪除操作線(xiàn)程安全{//
將
obj
移到
access
list
末端[_accessesremoveObjectIdenticalTo:
obj];[_accessesaddObject:
obj];}obj->accessCount++;_totalAccesses++;return
obj->object;}Cache
添加-(void)setObject:(id)objforKey:(id)keycost:
(NSUInteger)num{_GSCachedObject*oldObject=[_objectsobjectForKey:
key];_GSCachedObject
*newObject;if(nil!=
oldObject){[selfremoveObjectForKey:
oldObject->key];}[self_evictObjectsToMakeSpaceForObjectWithCost:
num];newObject=[_GSCachedObject
new];//Retainedhere,releasedwhenobjis
dealloc'dnewObject->object=
RETAIN(obj);newObject->key=
RETAIN(key);newObject->cost=
num;if([objconformsToProtocol:
@protocol(NSDiscardableContent)]){newObject->isEvictable=YES;[_accessesaddObject:
newObject];}[_objectssetObject:newObjectforKey:key];RELEASE(newObject);_totalCost+=
num;}Cache
自動(dòng)清理方法可時(shí)自動(dòng)清理的判斷//
cost
在添加新
cache
值時(shí)指定的
cost//
_costLimit
是
totalCostLimit
屬性值if(_costLimit>0&&_totalCost+cost>
_costLimit){spaceNeeded=_totalCost+cost-
_costLimit;}//
只有當(dāng)
cost
大于人工限制時(shí)才會(huì)清理//
或者
cost
設(shè)置為0不進(jìn)行人工干預(yù)if(count>0&&(spaceNeeded>0||count>=
_countLimit))不要清理經(jīng)常訪(fǎng)問(wèn)的
objects//_totalAccesses
所有的值的訪(fǎng)問(wèn)都會(huì)
+1NSUIntegeraverageAccesses=(_totalAccesses/count*0.2)+
1;//accessCount
每次
obj
取值時(shí)會(huì)
+1if(obj->accessCount<averageAccesses&&
obj->isEvictable)清理前準(zhǔn)備工作NSUIntegercost=
obj->cost;obj->cost=
0;//
不會(huì)被再次清除obj->isEvictable=
NO;//
添加到
remove
list
里if
(_evictsObjectsWithDiscardedContent){[evictedKeysaddObject:
obj->key];}_totalCost-=
cost;//
女果已經(jīng)釋放了足夠空間就不用后面操作了if(cost>spaceNeeded){break;}spaceNeeded-=
cost;清理時(shí)執(zhí)行回調(diào)-(void)removeObjectForKey:
(id)key{_GSCachedObject*obj=[_objectsobjectForKey:
key];if(nil!=
obj){[_delegatecache:selfwillEvictObject:
obj->object];_totalAccesses-=obj->accessCount;[_objectsremoveObjectForKey:key];[_accessesremoveObjectIdenticalTo:
obj];}}NSCache
在
SDWebImage
的運(yùn)用(UIImage*)imageFromMemoryCacheForKey:(NSString*)key
{return[self.memCache
objectForKey:key];}(UIImage*)imageFromDiskCacheForKey:(NSString*)key
{//
僉查
NSCache
里是否有UIImage*image=[self
imageFromMemoryCacheForKey:key];if(image)
{returnimage;}//
從磁盤(pán)里讀UIImage*diskImage=[self
diskImageForKey:key];if(diskImage&&self.shouldCacheImagesInMemory){NSUIntegercost=SDCacheCostForImage(diskImage);[self.memCachesetObject:diskImageforKey:key
cost:cost];}return
diskImage;}控制
App
的
Wake
次數(shù)喚起這個(gè)過(guò)程會(huì)有比較大的消耗通知,VoIP,定位,藍(lán)牙都會(huì)使設(shè)備從
Standby
狀態(tài)喚起定位方法的選擇連續(xù)的位置更新:startUpdatingLocation延時(shí)有效定位:allowDeferredLocationUpdatesUntilTraveled:
timeout:重大位置變化:startMonitoringSignificantLocationChanges區(qū)域監(jiān)測(cè):startMonitoringForRegion:(CLRegion
*)女可預(yù)防這些性能問(wèn)題需要刻意預(yù)防么?堅(jiān)持幾個(gè)原則優(yōu)化計(jì)算的復(fù)雜度從而減少
CPU
的使用在應(yīng)用響應(yīng)交互的時(shí)候停止沒(méi)必要的任務(wù)處理設(shè)置合適的
QoS將定時(shí)器任務(wù)合并,讓
CPU
更多時(shí)候處于
idle
狀態(tài)女可僉查?監(jiān)聽(tīng)主線(xiàn)程用
CFRunLoopObserverCreate
創(chuàng)建—個(gè)觀察者接受
CFRunLoopActivity
的回調(diào)用
CFRunLoopAddObserver
將觀察者添加到CFRunLoopGetMain()
主線(xiàn)程
Runloop
的kCFRunLoopCommonModes
模式下進(jìn)行觀察創(chuàng)建—個(gè)子線(xiàn)程來(lái)進(jìn)行監(jiān)控根據(jù)兩個(gè)
Runloop
的狀態(tài)
BeforeSources
和
AfterWaiting在區(qū)間時(shí)間是否能檢測(cè)到來(lái)判斷是否卡頓女可打印堆棧信息保存現(xiàn)場(chǎng)task_threads
取到所有的線(xiàn)程thread_act_array_tthreads;//int組成的數(shù)組比女thread[1]=5635mach_msg_type_number_t
thread_count
=0;//mach_msg_type_number_t
是
int
類(lèi)型consttask_tthis_task=mach_task_self();
//int//根據(jù)當(dāng)前
task
獲取所有線(xiàn)程kern_return_tkr=task_threads(this_task,&threads,
&thread_count);thread_info獲取線(xiàn)程詳細(xì)信息if(thread_info((thread_act_t)thread,THREAD_BASIC_INFO,(thread_info_t)threadInfo,&threadInfoCount)==KERN_SUCCESS)
{threadBasicInfo=
(thread_basic_info_t)threadInfo;if(!(threadBasicInfo->flags&TH_FLAGS_IDLE))
{threadInfoSt.cpuUsage=threadBasicInfo->cpu_usage/
10;threadInfoSt.userTime=
threadBasicInfo->system_time.microseconds;}}thread_get_state獲取線(xiàn)程里所有棧的信息_STRUCT_MCONTEXT
machineContext;
//線(xiàn)程棧里所有的棧指針//通過(guò)
thread_get_state
獲取完整的
machineContext
信息,包含
thread
狀態(tài)信息mach_msg_type_number_tstate_count=smThreadStateCountByCPU();kern_return_tkr=thread_get_state(thread,smThreadStateByCPU(),(thread_state_t)&machineContext.
ss,
&state_count);棧結(jié)構(gòu)體保存棧數(shù)據(jù)//為通用回溯設(shè)計(jì)結(jié)構(gòu)支持棧地址由小到大,地址里存儲(chǔ)上個(gè)棧指針的地址typedefstructSMStackFrame
{conststructSMStackFrame*const
previous;constuintptr_t
return_address;}
SMStackFrame;SMStackFramestackFrame=
{0};//通過(guò)?;分羔槴@取當(dāng)前棧幀地址constuintptr_tframePointer=
smMachStackBasePointerByCPU(&machineContext);if(framePointer==0||smMemCopySafely((void*)framePointer,&stackFrame,sizeof(stackFrame))!=KERN_SUCCESS)
{return@"Failframe
pointer";}for(;i<32;i++)
{buffer[i]=
stackFrame.return_address;if(buffer[i]==0||stackFrame.previous==0||smMemCopySafely(stackFrame.previous,&stackFrame,sizeof(stackFrame))!=KERN_SUCCESS)
{break;}}棧信息符號(hào)化獲取
mach_header
和
slide計(jì)算
ASLR
偏移量//根據(jù)
image
的序號(hào)獲取
mach_headerconststructmach_header*machHeader=
_dyld_get_image_header(idx);//返回
image_index
索引的
image
的虛擬內(nèi)存地址
slide
的數(shù)量,女果
image_index
超出范圍返回0//動(dòng)態(tài)鏈接器加載
image
時(shí),image
必須映射到未占用地址的進(jìn)程的虛擬地址空間。動(dòng)態(tài)鏈接器通過(guò)添加—個(gè)值到
image
的基地址來(lái)實(shí)現(xiàn),這個(gè)值是虛擬內(nèi)存
slide
數(shù)量constuintptr_timageVMAddressSlide=
(uintptr_t)_dyld_get_image_vmaddr_slide(idx);///wiki/Address_space_layout_randomizationconstuintptr_taddressWithSlide=address-
imageVMAddressSlide;獲取符號(hào)表的虛擬內(nèi)存偏移量//LC_SYMTAB
描述了
LINKEDIT
segment
內(nèi)查找字符串和符號(hào)表的位置if(loadCmd->cmd==LC_SYMTAB)
{//獲取字符串和符號(hào)表的虛擬內(nèi)存偏移量。conststructsymtab_command*symtabCmd=(structsymtab_command*)cmdPointer;constnlistByCPU*symbolTable=(nlistByCPU*)(segmentBase+
symtabCmd->symo?);constuintptr_tstringTable=segmentBase+
symtabCmd->stro?;找到最匹配的符號(hào)地址//給定的偏移量是文件偏移量,減去
LINKEDIT
segment
的文件偏移量獲得字符串和符號(hào)表的虛擬內(nèi)存偏移量uintptr_tsymbolBase=
symbolTable[iSym].n_value;uintptr_tcurrentDistance=addressWithSlide-
symbolBase;//尋找最小的距離
bestDistance,因?yàn)?/p>
addressWithSlide
是某個(gè)方法的指令地址,要大于這個(gè)方法的入口。//離
addressWithSlide
越近的函數(shù)入口越匹配if((addressWithSlide>=symbolBase)&&(currentDistance<=bestDistance)){bestMatch=symbolTable+
iSym;bestDistance=
currentDistance;}獲取更多信息更細(xì)化的測(cè)星時(shí)間消耗,找到耗時(shí)方法給優(yōu)化定個(gè)目標(biāo),比如某場(chǎng)景響應(yīng)操作在
100ms
內(nèi)完成女可獲取到更多信息呢?—張圖片hook
objc_msgSend
方法能夠獲取所有被調(diào)用的方法,facebook的
fishhook/facebook/fishhook記錄深度就能夠得到方法調(diào)用的樹(shù)狀結(jié)構(gòu),InspectiveC/DavidGoldman/InspectiveC通過(guò)執(zhí)行前后時(shí)間的記錄能夠得到每個(gè)方法的耗時(shí)獲取方法調(diào)用樹(shù)結(jié)構(gòu)設(shè)計(jì)兩個(gè)結(jié)構(gòu)體CallRecordtypedefstructCallRecord_
{id
obj; //object_getClass
得到
ClassNSStringFromClass
得類(lèi)名SEL
_cmd;
//通過(guò)
NSStringFromSelector
方法能夠得到方法名uintptr_t
lr;int
prevHitIndex;char
isWatchHit;}
CallRecord;ThreadCallStacktypedefstructThreadCallStack_
{CallRecord
*stack;int
allocatedLength;int
index;
//index
記錄方法樹(shù)的深度…}
ThreadCallStack;存儲(chǔ)讀取ThreadCallStackstaticinlineThreadCallStack
*getThreadCallStack()
{ThreadCallStack*cs=
(ThreadCallStack*)pthread_getspecific(threadKey);
//讀取if(cs==NULL)
{cs=
(ThreadCallStack*)malloc(sizeof(ThreadCallStack));...cs->stack=
(CallRecord*)calloc(DEFAULT_CALLSTACK_DEPTH,sizeof(CallRecord));
//分配
CallRecord
默認(rèn)空間...pthread_setspecific(threadKey,
cs);
//保存數(shù)據(jù)}return
cs;}記錄方法調(diào)用深度//開(kāi)始時(shí)staticinlinevoidpushCallRecord(idobj,uintptr_tlr,SEL_cmd,ThreadCallStack*cs)
{intnextIndex=
(++cs->index);
//增加深度if(nextIndex>=cs->allocatedLength)
{cs->allocatedLength+=
CALLSTACK_DEPTH_INCREMENT;cs->stack=(CallRecord*)realloc(cs->stack,cs->allocatedLength*
sizeof(CallRecord));cs->spacesStr=(char*)realloc(cs->spacesStr,cs->allocatedLength+
1);memset(cs->spacesStr,'',
cs->allocatedLength);cs->spacesStr[cs->allocatedLength]=
'\0';}CallRecord*newRecord=
&cs->stack[nextIndex];newRecord->obj=
obj;newRecord->_cmd=_cmd;newRecord->lr=lr;newRecord->isWatchHit=
0;}//結(jié)束時(shí)staticinlineCallRecord*popCallRecord(ThreadCallStack*cs)
{return
&cs->stack[cs->index--];
//減少深度}objc_msgSend前后插入執(zhí)行方法目的是在調(diào)用前和調(diào)用后分別加入
pushCallRecord
和popCallRecord不可能編寫(xiě)—個(gè)保留未知參數(shù)并跳轉(zhuǎn)到
c
中任意函數(shù)指針的函數(shù),那么這就需要用到匯編來(lái)做到主要思路就是先入棧參數(shù),x0
第—個(gè)參數(shù)是傳入對(duì)象,x1
第二個(gè)參數(shù)是選擇器
_cmd然后交換寄存器中,將用于返回的寄存器
lr
移到
x1
里。先讓pushCallRecord
能夠執(zhí)行,再執(zhí)行原始的
objc_msgSend,保存返回值,最后讓
popCallRecord
能執(zhí)行Hook
msgsend
方法dyld
是通過(guò)更新
Mach-O
二進(jìn)制的
DATA
segment
特定的部分中的指針來(lái)邦定
lazy
和
non-lazy
符號(hào)通過(guò)確認(rèn)傳遞給
rebind_symbol
里每個(gè)符號(hào)名稱(chēng)更新的位置就可以找出對(duì)應(yīng)替換來(lái)重新綁定這些符號(hào)遍歷
dyld//首先是遍歷
dyld
里的所有的
image,取出
image
header
和
slide。注第—次調(diào)用時(shí)主要注冊(cè)
callback。if(!_rebindings_head->next)
{_dyld_register_func_for_add_image(_rebind_symbols_for_image);}else
{uint32_tc=
_dyld_image_count();for(uint32_ti=0;i<c;i++)
{_rebind_symbols_for_image(_dyld_get_image_header(i),_dyld_get_image_vmaddr_slide(i));}}找出符號(hào)表相關(guān)
Commandsegment_command_t*cur_seg_cmd;segment_command_t*linkedit_segment=NULL;structsymtab_command*symtab_cmd=NULL;structdysymtab_command*dysymtab_cmd=
NULL;uintptr_tcur=(uintptr_t)header+
sizeof(mach_header_t);for(uinti=0;i<header->ncmds;i++,cur+=cur_seg_cmd->cmdsize)
{cur_seg_cmd=(segment_command_t
*)cur;if(cur_seg_cmd->cmd==LC_SEGMENT_ARCH_DEPENDENT)
{if(strcmp(cur_seg_cmd->segname,SEG_LINKEDIT)==0)
{linkedit_segment=
cur_seg_cmd;}}elseif(cur_seg_cmd->cmd==LC_SYMTAB)
{symtab_cmd=(struct
symtab_command*)cur_seg_cmd;}elseif(cur_seg_cmd->cmd==LC_DYSYMTAB)
{dysymtab_cmd=(struct
dysymtab_command*)cur_seg_cmd;}}
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 肺炎病人用藥護(hù)理
- 雞腺病毒培訓(xùn)課件
- 寵物急救技能培訓(xùn)課件
- 港口電氣安全培訓(xùn)
- Excel初級(jí)入門(mén)培訓(xùn)
- 政法大學(xué) 法律碩士
- 公司行政司機(jī)培訓(xùn)課件
- 財(cái)務(wù)人員防詐騙宣傳
- 論文投稿發(fā)表
- 機(jī)床知識(shí)培訓(xùn)課件模板
- 美國(guó)《GENIUS法案》:合規(guī)穩(wěn)定幣的監(jiān)管框架
- 2025至2030中國(guó)控制按鈕開(kāi)關(guān)行業(yè)產(chǎn)業(yè)運(yùn)行態(tài)勢(shì)及投資規(guī)劃深度研究報(bào)告
- 臨商銀行股份有限公司招聘筆試真題2024
- 2025廣東高考物理試題(大題部分)+評(píng)析
- DB31-T 1593-2025 基于自動(dòng)駕駛功能的公交運(yùn)營(yíng)技術(shù)要求
- 醫(yī)院純水系統(tǒng)管理制度
- 2025年中考英語(yǔ)考前沖刺押題模擬試卷 3套(含答案)
- 鄉(xiāng)村基層工作筆試題目及答案
- CJ/T 258-2014纖維增強(qiáng)無(wú)規(guī)共聚聚丙烯復(fù)合管
- 2025年小升初語(yǔ)文復(fù)習(xí):積累運(yùn)用 專(zhuān)項(xiàng)匯編(含答案)
- 靜脈留置針大賽理論考核考試試題及答案
評(píng)論
0/150
提交評(píng)論