如何讓手遊記憶體佔用更小?從記憶體消耗iOS實時統計開始
為什麼iOS記憶體使用過多會崩潰,效能會下降?騰訊遊戲學院專家Devlin在本文給瞭解釋,並且給出了統計記憶體的示例。
一,問題
在之前的手遊專案中,記憶體使用過多,都開始崩潰了,所以得做iOS記憶體統計。記憶體統計有好幾種方法:XCode記憶體使用統計、UnityInternalProfile記憶體統計,Mono記憶體統計等方法。
二、測試研究
但是XCode統計需要連手機,UnityInternalProfile的記憶體統計值與XCode記憶體統計值差距又太大,崩潰時的記憶體值跟誰有關係?如何在手機上自己顯示記憶體總量?後面就自己琢磨怎樣實現一個適合的記憶體統計功能。
研究了下UnityInternalProfile,發現它拿的是mach_base_task_info裡的resident_size(實體記憶體佔用)。
然後我做了個測試,每幾幀分配使用一定大小的記憶體,然後列印出xcode統計的記憶體和resident_size。
橫座標是時間,縱座標是記憶體。
resident_size值的增長隨著記憶體增長,但增長到一定程度就不怎麼變了,當時猜測可能是被壓縮了,查資料(MacOS有使用記憶體壓縮技術)和程式碼,發現iOS還有task_vm_info 這個結構體,裡面剛好有compress這項。
然後增加compress這項數值的輸出,重新測試!
在記憶體使用持續增加過程中,當resident_size(實體記憶體)不再增加時,compress這項線性增長。
三、推論
由圖可以看出:實際記憶體使用 = resident + compress。由此可以認為iOS通過壓縮記憶體來減少記憶體佔用。
並且在測試過程中,發現當實際使用記憶體達到系統實體記憶體一半時,系統會不斷髮送memorywarning的警告,達到60%時就會Q掉App。
四、應用
現在只需要實時拿到task_vm_info裡的resident 和 compress 就可以統計App的實際記憶體的使用量了,對於Unity手機專案來說,需要寫Native和C#程式碼,幸運的是,我已經幫你把程式碼寫好了。
在XCodePostProcess::OnPostProcessBuild()里加入如下程式碼,會在Unity生成的XCode工程自動插入如下Native程式碼:
XClass AppRender = new XClass(pathToBuiltProject + "/Classes/UnityAppController+Rendering.mm");
if( AppRender != null)
{
string TCode = "";
TCode += "#include <mach/mach_time.h>\n";
TCode += "#include <mach/mach.h>\n";
TCode += "#include <mach/mach_host.h>\n";
TCode += "#include <mach/task_info.h>\n";
TCode += "#include <mach/task.h>\n";
TCode += "static float GetTotalPhysicsMemory( )\n";
TCode += "{\n";
TCode += " kern_return_t kr;\n";
TCode += " mach_msg_type_number_t info_count = TASK_VM_INFO_COUNT;\n";
TCode += " task_vm_info_data_t vm_info;\n";
TCode += " kr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vm_info, &info_count);\n";
TCode += " if (kr == KERN_SUCCESS) return (float)(vm_info.compressed + vm_info.resident_size) / 1024.0 / 1024.0;\n";
TCode += " return 0;\n";
TCode += "}\n";
TCode += "extern \"C\" float _Get_Profiler_TotalPhysicMemory(){return _fLockStepPhysicMemory;}\n";
TCode += "extern \"C\" void UnityRepaint()";
AppRender.Replace("extern \"C\" void UnityRepaint()",TCode );
}
在UnityC#里加入以下託管程式碼,呼叫 Get_Profiler_TotalPhysicMemory()即可實時拿到記憶體使用值。
#if ( UNITY_IPHONE && !UNITY_EDITOR )
[DllImport("__Internal")]
static extern float _Get_Profiler_TotalPhysicMemory( );
public static float Get_Profiler_TotalPhysicMemory( )
{
return _Get_Profiler_TotalPhysicMemory( );
}
#endif
五、補充
由於系統有分頁機制,即你申請使用1位元組的記憶體,系統也有可能會給你一整頁(16k大小的物理頁),所以會導致這裡的實際記憶體使用量(記憶體分頁總和)與XCode記憶體統計(精確統計)不完成相等,但大致符合一定比例。
關於騰訊遊戲學院專家團
如果你的遊戲也富有想法充滿創意,如果你的團隊現在也遇到了一些開發瓶頸,那麼歡迎你來聯絡我們。騰訊遊戲學院聚集了騰訊及行業內策劃、美術、程式等領域的遊戲專家,我們將為全世界的創意遊戲團隊提供專業的技術指導和遊戲調優建議,解決團隊在開發過程中遇到的一系列問題。
申請專家資源請前往:
https://gwb.tencent.com/cn/tutor
來源:騰訊GWB遊戲無界
原文:https://mp.weixin.qq.com/s/s4tXl7KnjrDSnftbQSeiDg
相關文章
- filebeat實踐-記憶體佔用-最大記憶體佔用記憶體
- Redis記憶體——記憶體消耗(記憶體都去哪了?)Redis記憶體
- OpenResty 和 Nginx 的共享記憶體區是如何消耗實體記憶體的RESTNginx記憶體
- iOS底層原理(一):OC物件實際佔用記憶體與開闢記憶體關係iOS物件記憶體
- node計算記憶體佔用記憶體
- MySQL記憶體佔用計算公式MySql記憶體公式
- PHP計算出記憶體最高佔用.PHP記憶體
- 修改oracle記憶體佔用Oracle記憶體
- 資源記憶體佔用記憶體
- LOGMINER的記憶體消耗記憶體
- 如何檢視linux系統中空閒記憶體/實體記憶體使用/剩餘記憶體Linux記憶體
- 如何檢視MySQL資料庫佔多大記憶體,佔用太多記憶體怎麼辦?MySql資料庫記憶體
- Win10系統中“系統和壓縮記憶體”佔用大量記憶體如何解決Win10記憶體
- win10如何查詢哪些應用記憶體佔用大 win10如何檢視軟體記憶體佔用Win10記憶體
- 好玩又不佔記憶體的手遊 記憶體小又能聯機的傳奇遊戲記憶體遊戲
- Redis Quicklist 竟讓記憶體佔用狂降50%?RedisUI記憶體
- 託管堆記憶體佔用記憶體
- influxdb記憶體佔用剖析UX記憶體
- 16g記憶體win10開機記憶體佔用高如何解決_16g記憶體win10開機記憶體就達55%怎麼辦記憶體Win10
- Unity手遊iOS記憶體分析和測試UnityiOS記憶體
- 計算機作業系統——虛擬記憶體與實體記憶體計算機作業系統記憶體
- 實體記憶體和虛擬記憶體記憶體
- Chrome 再次最佳化記憶體佔用問題,新增記憶體釋放開關Chrome記憶體
- AIX程式記憶體佔用數的計算AI記憶體
- AIX系統記憶體佔用率的計算AI記憶體
- Redis 實戰 —— 12. 降低記憶體佔用Redis記憶體
- EEPROM與記憶體Flash消耗能量計算記憶體
- iOS 記憶體管理iOS記憶體
- 獲取 Laravel 執行時間和記憶體消耗Laravel記憶體
- python物件的記憶體佔用Python物件記憶體
- mariadb 記憶體佔用優化記憶體優化
- 記憶體管理篇——實體記憶體的管理記憶體
- 如何釋放linux cache佔用的記憶體Linux記憶體
- iOS開發筆記(一):記憶體管理iOS筆記記憶體
- Linux程式記憶體佔用數的計算Linux記憶體
- win10如何降低chrome記憶體佔用_win10電腦chrome記憶體佔用過高怎麼辦Win10Chrome記憶體
- 一個導致JVM實體記憶體消耗大的BugJVM記憶體
- 虛擬記憶體到實體記憶體(32位)記憶體