zoukankan      html  css  js  c++  java
  • 如何让手游内存占用更小?从内存消耗iOS实时统计开始

    为什么iOS内存使用过多会崩溃,性能会下降?腾讯游戏学院专家Devlin在本文给了解释,如何让手游内存占用更小?从内存消耗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代码:

    XClass AppRender = new XClass(pathToBuiltProject + "/Classes/UnityAppController+Rendering.mm");
    if( AppRender != null)
    {
    string TCode = "";
    TCode += "#include <mach/mach_time.h> ";
    TCode += "#include <mach/mach.h> ";
    TCode += "#include <mach/mach_host.h> ";
    TCode += "#include <mach/task_info.h> ";
    TCode += "#include <mach/task.h> ";
    TCode += "static float GetTotalPhysicsMemory( ) ";
    TCode += "{ ";
    TCode += " kern_return_t kr; ";
    TCode += " mach_msg_type_number_t info_count = TASK_VM_INFO_COUNT; ";
    TCode += " task_vm_info_data_t vm_info; ";
    TCode += " kr = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vm_info, &info_count); ";
    TCode += " if (kr == KERN_SUCCESS) return (float)(vm_info.compressed + vm_info.resident_size) / 1024.0 / 1024.0; ";
    TCode += " return 0; ";
    TCode += "} ";
    TCode += "extern "C" float _Get_Profiler_TotalPhysicMemory(){return _fLockStepPhysicMemory;} ";
    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内存统计(精确统计)不完成相等,但大致符合一定比例。

  • 相关阅读:
    对MVC模式与MVVM模式的认识
    优雅降级和渐进增强
    入园第一天
    看看AQS阻塞队列和条件队列
    简单看看LockSupport和AQS
    简单看看LongAccumulator
    JUC中的原子操作类及其原理
    java并发基础知识
    简单看看es6解构赋值
    简单使用vue-cli
  • 原文地址:https://www.cnblogs.com/dyf214/p/12091936.html
Copyright © 2011-2022 走看看