出处:记一次内存优化的分享
公司游戏已经进行到最后一个阶段了,经过最后一次引擎升级之后使用的是3.3的版本。以前产品定位的目标是只需要兼容1G或者以上内存就可以,我们也一直没关注低内存的运行情况。现在发行渠道要去兼容512内存,这就不得对游戏进行优化了。
一般来说,游戏里比较容易出内存问题的地方是纹理资源和内存泄露。对于内存泄露来说,由于我们使用的是lua脚本进行逻辑开发,而且在测试的时候并不会出现内存持续高涨的情况,所以可以大概排除这种可能。
纹理资源的话我设计了一套类似LRU的淘汰算法,会内存紧张时候自动淘汰长时间不使用的资源(视内存情况)。而且统计内存中纹理占用比非常低,512M手机一般情况只使用25M的纹理。所以必须进一步探索内存消耗点了。
一、初略内存消耗检测:
开始主要使用的是adb shell dumpsys meminfo命令(感谢网易王杰同学热心指导),该命令可以准确统计AndroID进程的内存情况,特别是对于游戏App非常重要的Native Heap。配合游戏逻辑打开和关闭某些功能大概推测。并且把主要占内存的纹理资源和Lua(lua_gc(L,LUA_GCCOUNT,0))堆大小统计输出。
进过多次测试之后发现内存涨到一定高度不会持续高涨,排除泄露的情况。而且纹理占用比不是很高(不到30%)。而且在第一次进战斗后Lua内存占用非常大(20-30M)。分析后发现关卡波次(config_wave)表异常庞大导致,我们的配置是用lua表配置的,而且常驻内存。而config_wave有接近1W行, 单独加载它大约占14M内存,初用Lua不知啊!
除去lua heap的占用,还有剩下接近50%的内存,我一直以来的理解是,作为普通c++对象,是不太可能占用很多内存资源的,所以一直不太理解这个内存分布情况。所以还需要进一步分析。
二、进一步内存检测:
神奇的Google给了我一些指示:Native Heap分析和优化
关键流程是:
1、给系统安装libc_malloc_deBUG_leak.so:
上面描述的好像非常麻烦,要编译自己的ROM,但是小米手机自带(应该是开发版)这个库,正好找到一部米1。
2、开启libc.deBUG.malloc功能:
先Rootadb shell:控制台执行adb shell root获取Root权限。然后依次执行:
1 2 3 | adbshellsetproplibc.deBUG. malloc 1 adbshellstop adbshellstart |
手机会自动重启,然后可以通过getprop检查libc.deBUG.malloc变量是否被正确设置。
3、修改AndroID SDK DDMS的配置 ddms.cfg文件(我的是在C:\Users\xingyun\.androID目录下面)。添加"native=true",保存后重启DDMS,记得一定要从SDK中启动,Eclipse里的是没用的。会有一个Native Heap的选项卡,连接手机并且保证libc.deBUG.malloc变量设置正确后在界面选择自己的进程,点击snpshot Current Native Heap Usage,就会显示进程内所有NativeHeap的内存分配情况。
这里有个问题是只有内存分配地址,没有对应函数和符号。有一个Symbol Search Path,但是没什么用(发现是要用冒号隔开...冒号..不是会和windows的路径冲突吗?),最终放弃让它自己匹配符号。
有地址,可以通过addr2line(是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具)分析地址对应的符号。注意:这个工具需要的地址并不是DDMS dump出来的绝对地址,而是相对于内存so的地址!通过adb shell读取AndroID系统文件proc/[pID]/maps获取进程库的内存分布,会发现有很多库会有两份,找其中"r-xp"权限(可执行)的那条就可以了。比如我的查询过程是:DDMS里的地址为83071ef4,so在内存的地址是82000000,所以符号在so的地址是01071ef4。最后 addr2line 01071ef4 -e lib***.so -f 查到:
_ZN7cocos2d9Texture2D15initWithMipmapsEPNS_11_MipmAPInfoEiNS0_11PixelFormatEi /./renderer/CCTexture2D.cpp:672 |
很明显这是申请纹理时分配的内存。
但是这样分析效率太低。后来发现DDMS可以把结果导出成一个txt文件,如下图:
导出的txt文件里只有so文件名和地址,以及大小信息,所以写了个简单的脚本进行地址符号转换和分类统计。
最终转换出来这样的输出:
{total:76.59M, categorys:[ {name:Texture,total:24.06M, stacks:[ {tital:15.76M,count:10,size:3.52M, frames:[ _ZN7cocos2d9Texture2D15initWithMipmapsEPNS_11_MipmAPInfoEiNS0_11PixelFormatEi:/./renderer/CCTexture2D.cpp:672 _ZN7cocos2d9Texture2D12initWithDataEPKviNS0_11PixelFormatEiiRKNS_4Size:/./renderer/CCTexture2D.cpp:557 _ZN7cocos2d9Texture2D13initWithImageEPNS_5ImageENS0_11PixelFormat:/./renderer/CCTexture2D.cpp:794 _ZN7cocos2d9Texture2D13initWithImageEPNS_5Image:/./renderer/CCTexture2D.cpp:727 _ZN7cocos2d12TextureCache8addImageERKS:Cache.cpp:346(discriminator2) _Z34lua_cocos2dx_TextureCache_addImageP9lua_Stat:uto/lua_cocos2dx_auto.cpp:67552 ] }, {tital:4.89M,count:9,size:1.00M, frames:[ @H_502_245@ _ZN7cocos2d9Texture2D15initWithMipmapsEPNS_11_MipmAPInfoEiNS0_11PixelFormatEi:/./renderer/CCTexture2D.cpp:665 _ZN7cocos2d9Texture2D12initWithDataEPKviNS0_11PixelFormatEiiRKNS_4Size:/./renderer/CCTexture2D.cpp:557 _ZN7cocos2d9Texture2D13initWithImageEPNS_5ImageENS0_11PixelFormat:/./renderer/CCTexture2D.cpp:782 _ZN7cocos2d9Texture2D13initWithImageEPNS_5Image:/./renderer/CCTexture2D.cpp:727 _ZN7cocos2d12TextureCache8addImageERKS:Cache.cpp:346(discriminator2) ] {tital:2.00M,count:1,size:2.00M, frames:[ _ZN7cocos2d9Texture2D15initWithMipmapsEPNS_11_MipmAPInfoEiNS0_11PixelFormatEi:/./renderer/CCTexture2D.cpp:665 _ZN7cocos2d9Texture2D12initWithDataEPKviNS0_11PixelFormatEiiRKNS_4Size:/./renderer/CCTexture2D.cpp:557 _ZN7cocos2d9Texture2D13initWithImageEPNS_5ImageENS0_11PixelFormat:/./renderer/CCTexture2D.cpp:782 _ZN7cocos2d9Texture2D13initWithImageEPNS_5Image:/./renderer/CCTexture2D.cpp:727 ] 输出的是Json格式,一般编辑器对Json都有“收起内容”的支持,比较方便查看。 |
评论列表(0条)