如何让手游内存占用更小?从内存消耗iOS实时统计开始
一,問題
在之前的手游項目中,內存使用過多,都開始崩潰了,所以得做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代碼:
? ?? ???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()即可實時拿到內存使用值。
?
? ? [DllImport("__Internal")]
? ? static extern float _Get_Profiler_TotalPhysicMemory( );
? ? public static float Get_Profiler_TotalPhysicMemory( )
? ? {
? ?? ???return _Get_Profiler_TotalPhysicMemory( );
? ? }
#endif
五、補充
由于系統有分頁機制,即你申請使用1字節的內存,系統也有可能會給你一整頁(16k大小的物理頁),所以會導致這里的實際內存使用量(內存分頁總和)與XCode內存統計(精確統計)不完成相等,但大致符合一定比例。
關于騰訊游戲學院專家團
如果你的游戲也富有想法充滿創意,如果你的團隊現在也遇到了一些開發瓶頸,那么歡迎你來聯系我們。騰訊游戲學院聚集了騰訊及行業內策劃、美術、程序等領域的游戲專家,我們將為全世界的創意游戲團隊提供專業的技術指導和游戲調優建議,解決團隊在開發過程中遇到的一系列問題。
總結
以上是生活随笔為你收集整理的如何让手游内存占用更小?从内存消耗iOS实时统计开始的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 腾讯云为小游戏开发者升级工具箱 小游戏联
- 下一篇: 动作游戏老是卡?试试从这些方面提升流畅度