【实战记录】手游内存优化(内存泄露检测)

news2024/9/28 9:26:12

故事背景:
        手上有一个完整的页游项目,线上运营数据还不错,所以打算把这个项目手游化。因为这个项目本来就是用cocos的creator写的,所以手游化成本比较低,在修改了大概6~7个只能在页游上运行的接口后,游戏就成功在手机上跑起来了。当然,虽然在手机上顺利跑起来了,但还有大量的工作是需要做得,例如:把鼠标点击,鼠标滑动经过,鼠标滚轮相关的操作改成手机的点击操作,又或者很多界面上能显示清晰的字体,放到手机上就看得很吃力很辛苦了(省略一万字)。而当中比较蛋痛的问题就是今天的主题了--内存泄露……
        这个泄露存在很多原因,也不能怪做页游版的朋友。首先,这游戏在页游上运行并没有出现闪退等现象,一切都能正常运行,其次,部分地方有可能是他们故意不释放的,不释放有可能资源会被反复利用,下次使用时加载资源速度就更快了,等于空间换时间~ 当然,解释一万句,其实最终项目上还是有不少地方确实存在泄露……只是他们页游运行正常,PC版顶得住……

使用的游戏引擎:CocosCreator 2.4.5

PS:嫌字多废话多的可以直接拉到文章末端,有精简版……

一.内存检测工具

要做内存相关的优化,首先肯定是要看到内存的变化情况,这里我使用了2款工具去查看游戏的内存。

1.android-studio的Profiler

 他的优点是可以实时,动态的看着内存的变化,缺点是当内存上升到一定程度,就会像上图一样显示的数据变成0.7GB了。刚开始时,他显示的是如:456M这样的显示,我可以看到的内存变化最少值是1M,但变成G之后,内存变化的最少值变成了100M,这就不符合我的需求了。

为了更精准的查看内存的准确数据,我使用了第二种内存检查工具。

2.adb的dumpsys指令
adb shell dumpsys meminfo 包名

他能显示当前内存的使用情况且精准的KB,但只能显示输入指令那一刻的内存情况(虽然我尝试写过bat一直循坏调用这个指令,一直刷新着内存的情况,但依然不够工具1的动态显示那么直观)

在检测工具这块,我只找了两个显示内存的工具,而没有去寻找更多的工具(之前是有听说过有些工具会显示内存快照之类的,但后面我们也在游戏内部代码实现了类似的功能)

二.检查加载资源的入口函数

        通过检查后发现,所有资源的加载都指向了同一个类【AssetManager】,接着寻找这个类的相关方法,发现有【releaseUnusedAssets】【releaseAll】接口,尝试过后……出现各种问题,此路不通……

        接着发现【loadAny】【loadRemote】【load】等方法确实是有内存泄露风险的,个人感觉官方意思,这些接口使用者加载回来的资源,自己加载自己管理,load回来后可以使用addRef进行引用计数+1,使用完后可以用decRef进行引用计数减1,引用计数为0则释放资源。
        然后查看项目代码,发现这些相关接口,加载完资源后,既没有addRef也没有decRef,再继续深入打断点,发现资源的引用计数为0,当时以为他会在主循环中自动检测,引用计数为0就会自动释放(走弯路了呗),结果这里显示没有释放,需要主动调用decRef或者cc.assetManager.releaseAsset等方法来主动释放资源。

三.通过项目资源寻找内存主要泄露点

        因为项目不是新项目了,是一个代码量比较庞大的成熟老项目,即使发现某个接口存在内存泄露,可如果项目里面有上百个地方调用到相关接口,改起来还是工作量巨大,而且不能保证绝对安全。所以在这个老项目上,第一波优化方案我选择了允许部分内存泄露,先优先处理那些接口统一而又存在大量内存泄露的地方【改最少得地方,减最多的内存】。我们一共寻找到4个资源量比较大的地方【各功能模块的资源】【人物、坐骑、模型等资源】【spine动画】【地图资源】

1.【人物、坐骑、模型等资源】
经过检查后,没发现泄露。

2.【地图资源】
确认存在泄露,在地图模块对load回来的资源addRef,decRef就解决了。
游戏内存也从2G降到了1.6G

3.【spine动画】
这个一开始我是排除了他泄露的可能性的,检查过他有对资源进行引用计数管理和释放。而且在原有网页版上测试也没发现这块有存在泄露。后来使用了方法【四】(文章下面会详细说),才最终定位到spine动画存在泄露。
处理后,游戏内存从1.6G降到了接近1.1G的地步。

4.【各功能模块的资源】
这里一开始我们就觉得他存在泄露,项目里各模块都处理成一个独立的bundle,但他loadbundle后,没看到他removeBundle,然后我们尝试了removeBundle,内存是降了,但不明显只降了几十M。后来使用了方法【五】(文章下面会详细说),最终定位到动态load的prefab没释放,内存又减少了200M+

至此,内存从一开始的2G降到了不到900M,而且为了快而稳的处理这个问题,我们初步只是找了一些修改起来比较统一而且泄露比较大的地方进去处理(目标是改起来快而且安全)。后续如果有需要的话可以更进一步对那些已经确定泄露的地方进行优化,只是那些优化可能改几十个地方也就降低几M,10几M的内存。

四.控制变量

        先寻找一个内存增加了很多的地方,然后逐渐减少那一块加载的东西,最终找出内存泄露的地方。
        在我们项目中,我发现新手第一场战斗后,增加了不少的内存,然后就开始屏蔽人物,屏蔽特效,屏蔽UI等等,最终发现了spine动画没释放。
        最简单的屏蔽肯定是把创建那些资源的代码直接屏蔽掉,但有些时候却并不好用,例如战斗的人物如果不创建出来,战斗逻辑会出问题,又例如当前只是加载一个texture,加载完成后返回到代码逻辑中创建spriteFrame,你把load texture的代码屏蔽了,后续代码会出问题,你想把创建sprite的代码屏蔽掉,他分散在战斗中的每一个角落,所以这里我建议,例如像texture,在他创建的地方我们写死一张固定资源来加载,那他永远都只会加载那一张texture,虽然界面看着会各种奇怪(都是那张图),但我们只需要达到屏蔽资源测试内存的目的不就可以了么? 人物角色也是一样,可以加载同一个,这样就会让原本加载几十个的资源变成加载一个,达到屏蔽的效果,依然可以看出最终泄露是出在哪一块上。

五.内存快照

        开篇时就有提到过有些内存检测工具有这类功能,一来懒得研究,二来在代码里写也不复杂,就自己做了个类似的东西了。

        打开界面前,记录下assetsManager里面当前的所有资源,然后打开界面关掉界面,再获取当前assetsManager里面的所有资源,并和打开界面前进行比较,在后台输出新增的资源。
        我们期待的必然是打开界面前和关闭界面后基本没有新增资源的,可结果显示是糟糕的,测试中尝试把游戏大部分的系统界面都点开一遍然后关闭掉,发现assetsManager里面新增了600多个资源,后来定位到一个统一的地方,把对应的perfab释放后,再测试时新增资源数已经减到剩下150个了。
剩下这些资源就没统一的地方可以改了,都是散布在各个模块代码里面load的资源,本着【改最少得地方,减最多的内存】的思想,剩下的也放后续优化里面了。例如这150个里面有近半都是icon资源,可能我要改20~30个地方最终减少不到1M的内存占用……

六.通过手动GC释放内存

        我是不太了解java的底层GC机制的,只知道他会间隔一段时间(具体什么规则也不太清楚=。=)才会GC一次,所以即使你的资源在游戏内释放掉了,其实他并没有真正的释放内存,要等到java的GC时才会真正把内存释放掉,这意味着我们游戏的平均内存会因为没GC而变得更高,当然GC也要消耗性能,我们也不能一直无限的去GC,这样我们就可以找一些游戏节点去进行GC了,例如切换场景的时候,或者某个界面打开时占用了大量的资源在他关闭的时候手动GC一下。

------------------------------------------------------精简版------------------------------------------------------

第一点:【内存检测工具】介绍了2款内存检测工具
第二点:【查内存泄露的方法】通过查找加载资源的接口来寻找资源是否有泄露
第三点:
【查内存泄露的方法】通过检查游戏内比较大的资源是否有释放,来寻找内存泄露比较多的地方(因为一般内存泄露比较明显的地方多数是加载了较大的资源没有释放)
第四点:【查内存泄露的方法】找到一个游戏内比较明显有泄露的地方,然后把那地方的东西,一块块屏蔽掉,通过控制变量最终找到泄露的点。
第五点:【查内存泄露的方法】通过两次内存快照之间新增的内存点,去寻找泄露
第六点:【内存优化】手动GC,及早清理没使用到的内存


 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/571209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansible介绍

文章目录 Ansible介绍Ansible的架构为什么要有Ansible TowerAnsible Tower Ansible介绍 Ansible是一种自动化工具,可以用于自动化部署、配置和管理IT基础设施。它是一种基于Python的开源软件,提供了一个简单易用的语言和工具集,使得自动化管…

内网渗透—代理Socks协议、路由不出网、SMB绕过、CS-MSF控制上线

内网渗透—代理Socks协议、路由不出网、SMB绕过、CS-MSF控制上线 1. 前言1.1. 实验背景1.2. 环境准备1.2.1. 环境介绍1.2.2. 环境测试 2. CS上线2.1. Windows2008上线2.2. Windows2003上线2.2.1. 设置socks代理2.2.2. 设置正向连接2.2.3. 生成木马2.2.4. 上线木马 2.3. Windows…

Flutter数据库操作看这一篇就够了

文章目录 Flutter常用数据库操作库最常用的sqflite介绍简介举例 依赖sqflite,单例模式封装一个sqlite操作类说明initDb说明conflictAlgorithm说明 Flutter常用数据库操作库 Flutter是一种跨平台的移动应用程序开发框架,支持使用多种类型的数据库进行数据存储和管理…

【CSDN快速获得铁粉小经验】厉昱辰的经验分享

如何快速的涨粉呢?今天将带领大家一起涨粉喽🥰🥰🥳🥳 一、最低阅读量过滤 官方算法进行最低阅读量过滤,阅读量太低的直接不参与热榜计算,刚创建的文章应该在其他渠道有一些冷启动的过程。但是阅…

c++ 11标准模板(STL) std::map(四)

定义于头文件<map> template< class Key, class T, class Compare std::less<Key>, class Allocator std::allocator<std::pair<const Key, T> > > class map;(1)namespace pmr { template <class Key, class T, clas…

150套开发板免费送!还有5G手机拿?米尔RZ/G2L开发板创意秀

人间最美五月天 不负韶华不负卿 米尔又来送板子了 不是3套&#xff0c;也不是4套 150套米尔RZ/G2L开发板 送&#xff01;免费&#xff01;板卡不回收&#xff01; 这是什么样的有奖活动&#xff1f; 米尔RZ/G2L开发板创意秀 为感谢广大客户一直以来的支持&#xff0c;推动…

15 个非常流行的VsCode插件,让你的编码效率倍增!

VS Code已经成为了最受欢迎的代码编辑器之一。 它的简洁性、易用性和可扩展性使得它成为了许多开发者的首选。 而在VS Code中&#xff0c;插件是其最大的卖点之一。 通过安装插件&#xff0c;你可以将VS Code打造成一个功能强大的开发环境&#xff0c;从而提高你的编码效率。…

【2023A题】电采暖负荷参与电力系统功率调节的技术经济分析(思路、代码)

目录 &#x1f4a5;1 概述 &#x1f4da;2 Matlab代码实现 &#x1f389;3 参考文献 &#x1f308;4 运行结果 &#x1f4a5;1 概述 建设以新能源为主体的新型电力系统是应对全球气候变化挑战的重要举措。高比例新能源接入导致电力系统调节能力稀缺&#xff0c;亟需开发新的调…

Node版本管理器nvm的安装与使用

前言&#xff1a; 多项目新旧项目管理的时候&#xff0c;往往与依赖不同的node版本&#xff0c;不同的版本对其他依赖的安装有一定的影响&#xff0c;因此我们需要对node的版本进行方便快捷管理和切换&#xff0c;如果直接卸载重装对应版本&#xff0c;切换项目再次卸载重装明显…

word打印为pdf去掉批注和修订记录

对于这个问题某乎上充斥着垃圾回答&#xff0c;大多引流到自家开发的pdf产品上。其实背后的方法都是一样的&#xff0c;就是关掉批注&#xff0c;用word自带的功能就能解决&#xff0c;凡是word编辑软件都有类似功能 直接用word打印为pdf后的效果 下图为打印出来的pdf文件&…

杜绝开源依赖风险,许可证扫描让高效合规「两不误」

目录 开源许可证及其常见类型 开源许可证扫描是软件研发过程中&#xff0c;不可或缺的工具 极狐GitLab 开源许可证扫描的优势与应用 Step 1&#xff1a;启用及设置许可证策略 Step 2&#xff1a;自动创建策略文件存放项目 Step 3&#xff1a;查看许可证合规情况 Step 4&…

<Linux开发>驱动开发 -之-gpio子系统

&#xff1c;Linux开发&#xff1e;驱动开发 -之-gpio子系统 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移植过程详细记录&…

vue实现倒计时功能

vue实现倒计时功能 首先我们需要一个 Vue. js的函数&#xff0c;这个函数用于实现倒计时&#xff0c;这里我们采用 vue. js的 import来实现&#xff0c;这是 vue. js的一个特殊功能&#xff0c;将函数调用的参数以列表的形式加入到函数中&#xff0c;当在函数执行完后返回结果。…

Java基础--->IO流(2)【常见IO模型】

文章目录 计算机角度IO操作系统IO常见的IO模型Java 中 3 种常见 IO 模型BIO&#xff08;BlockingI/O&#xff09;【同步阻塞IO】NIO&#xff08;Non-blocking/New I/O&#xff09;【非阻塞IO】IO多路复用AIO&#xff08;Asynchronous I/O&#xff09;【异步IO】 计算机角度IO 根…

进攻中型SUV,蔚来/小鹏的智能化「满配」能否撬动需求

251.29万辆&#xff0c;这是2022年中国市场&#xff08;不含进出口&#xff09;乘用车中型SUV交出的答卷&#xff0c;交付量仅次于紧凑型SUV&#xff0c;排名细分市场第二。在这份成绩单中&#xff0c;有几个数字特别醒目。 1、31.64万辆&#xff0c;这是排名这个细分市场交付量…

chatgpt赋能python:Python交易股票:掌握交易技巧,开启财富增长之路

Python 交易股票&#xff1a;掌握交易技巧&#xff0c;开启财富增长之路 股票市场一直以来都是吸引人们收益的地方&#xff0c;不断变化的市场行情也让每一位投资者都不得不面对各种风险。然而&#xff0c;如果您懂得运用好 Python 来交易股票&#xff0c;就能够更好地理解市场…

【软考-中级】系统集成项目管理工程师 【14 采购管理】

持续更新。。。。。。。。。。。。。。。 【第十四章】采购管理 2 分 14.1采购管理的相关概念和主要过程14.1.1 概念和术语14.1.2 采购管理的主要过程 14.2编制采购管理计划14.2.1编制采购计划的输入、输出14.2.2用于编制采购计划过程的技术和方法14.2.3工作说明书 历年真题202…

小程序外包开发上线流程

小程序有非常多的优势&#xff0c;无需下载安装、使用方便、开发成本低、覆盖广泛、轻量级、方便推广&#xff0c;这些特点使得小程序非常适合场景不太复杂的场合&#xff0c;这些年出现了大量的小程序。今天和大家分享一下小程序的一些特点和上线流程&#xff0c;希望对大家有…

C#,码海拾贝(21)——“全选主元高斯消去法“求解“线性方程组“的C#源代码,《C#数值计算算法编程》源代码升级改进版

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static class LEquations { /// <summary> /…

mysql倒库操作遇到的问题

背景&#xff1a;本地windows 10安装了mysql数据库后&#xff0c;需要把远程库的表结构和数据全部导入进来。 操作&#xff1a;导出数据库&#xff0c;导入数据库。 第一步&#xff1a;导出数据库 使用dump命令即可。 登陆mysql数据库 mysql -hhost --default-character-s…