我们公司的一个 MMORPG 项目最近在内存方面碰到了红线,昨天开会讨论了一下。我提出了一个改进方案,写篇 blog 记录一下。

问题是这样的。在当下的手机及平板硬件设备条件下,操作系统留给应用的可用内存并不多,大约只有 500M 左右。

和 PC 环境不同,手机上是交换分区的机制来对应一些临时突发性内存需求的。而手机必须保证一些系统服务(某些高优先级后台业务)的运行,所以在接电话、收取推送等等意外任务发生时,有可能多占用一些内存,导致操作系统杀掉前台任务让出资源。

根据实际测试,游戏想跑在当前主流高端手机上必须把自己的内存占用峰值控制在 400M 内存以下,350 M 会是一个合理的值,而这个值是远远低于 10 年前的 PC 游戏标准的。而我们的项目却是一个写实类型的 拥有大场景的 MMORPG 。

Unity3D 是在智能手机普及以前设计的,远没有料到会被广泛用于手机游戏的制作。它在设计之初并没有为低内存环境考虑。内存使用太粗犷,是在使用 Unity 开发 MMORPG 项目时最被吐槽的一点。

为手机游戏定制游戏引擎,最特别的,和 PC 游戏不同的两点就是内存必须严格控制、能耗必须严格控制。比如在我们开发的 ejoy2d 中,会为资源数据中的项目引用定制短指针,即资源内部的相互引用使用 32bit 偏移量来代替 64bit 指针,每个指针节省出 4 字节内存;变换矩阵使用 6 个 32bit 的定点数,资源中相同矩阵共享一份数据;资源数据尽量连续存放,避免小数据块太多造成内存碎片浪费内存等等。这些显然是 Unity 没花精力去做的。在 PC 上,省下几M 几十M 内存微不足道,但在手机上很可能就是生死之间。

ps. 能耗问题是另一个有趣点。在 PC 上你可以通过多线程并行,压榨出高 fps ,可以不管 CPU 多烫;但是到了手机上,即使 CPU 8 核心已经是标配,还是尽量不要这么做。因为在总任务相同的情况下,单线程能做完的工作只要拆分到多线程上完成,就一定意味着总工作量增加(至少增加了线程间协调的工作)。增加了总能耗。玩家是不想玩一个插着充电线也会玩关机,手机滚烫的游戏的。这个问题有机会我另写一篇 blog 展开,今天是想谈谈内存。


在我们最近的测试中,在较坏情况下,我们的游戏会占到 360M 内存左右,已经接近了内存红线,所以要考虑进一步的优化。其中,较大的一块是游戏场景,占了 120M 内存。

有趣的是,这 120M 内存中只有大约 50M 是用于场景上物件的贴图、模型等等资源数据(注:我们项目没有使用静态批次合并,那样更消耗内存。);也就是说,有 70M 内存用于构建场景本身的结构。所以,并非让美术人员尽量复用同样模型的花花草草就可以省下内存的。换句让美术人员更容易明白的说法,我们的场景中摆的东西太多了,不是减少贴图用量,把同一块石头到处摆可以解决的。这和过去制作 PC 游戏的常识不同。

所以,大部分现有的手机 MMORPG 的画风偏卡通幻想风格不是没有道理。因为那样,可以用有悖现实的物件比例,场景物件个头大,就可以用更少的数量去充斥场景。而写实风讲将就细节丰富,用诸多细节去填满视野。在过去 PC 上,这不是问题,只要少做点独特的模型,少用贴图就能把内存降下来,手机上不行了。


我们并非刚刚意思到这点。一开始,开发人员就针对大场景制定了技术解决方案。

我们在场景上,认为设定了若干包围盒,勾画出一块块小区域。一旦玩家离开包围盒太远,程序就会把包围盒里面的物件卸载出内存。然后在美术设计上,不让玩家有可以从远处观望的角度。我们的美术风格会尽量保证场景细而精致、不追求空旷宏大的场面。

但这还做的不够,我提出了一个改进方案。


  1. 保留包围盒方案。但是包围盒略微扩大,允许包围盒重叠,并可以用多个包围盒来定义一个区域。同一个场景物件只可以属于一个区域,即使它的位置在多个区域内。(区域可以重叠)

  2. 所有物件都标记分类出外观物件和细节物件。比如一个城市的城墙就是外观物件,而城内的所有东西都是细节物件;一片树林的大颗植物是外观物件,地面的花花草草是细节物件。一般情况下,大部分物件都默认是细节物件,只有少数需要远观的才标记成外观。这点,其实原本就做了视距分层,只不过是为了在渲染时做显示剔除用的,并没有用于控制内存。而这次,需要对外观物件和细节物件单独打包分类,便于分开卸载。

  3. 当玩家处于一个区域内部时,必须保证这个区域的外观物件和细节物件都加载到内存。如果之前并不在内存,也需要开启异步加载的流程。当一个玩家距离另一个区域比较近时,只需要确保该区域的外观物件在内存即可,可以卸载任何不在区域的细节物件。


在以上改进方案里,把包围盒扩大以及允许多个包围盒一起构成区域,是为了改进数据加载的时机。单一用距离判断会有瑕疵。比如在城墙外,即使隔的很近也不需要加载城内的细节。而我们完全可以在城门外加一个缓冲的小区域并入城市区域,只要玩家一踩到城门口,城内的细节加载流程就开始启动了。

而允许区域重叠,并让物件唯一归属于单一区域则可以解决城门外的细节物体提前加载时机。城外的这块缓冲区上的物件就不必归属到城市板块,它们早在玩家在城外活动时就加载完毕了。

Unity3D 的大场景内存优化的更多相关文章

  1. [原]unity3d ios平台内存优化(一)

    关于内存优化,人云亦云 各有己见.本文将通过设置Strpping Level ,减少内存使用. 先看三幅图: 1.没做任何优化,默认选项 2.设置Stripping level 为 Use micro ...

  2. Unity3D移动端内存优化(NGUI方面)

     Unity3D引擎技术交流QQ群:[21568554] 做3d移动端内存一直是人们头疼的问题,载入的资源释放了,还有其它的须要释放.比方ngui释放,事实上主要是NGUI的Texture和Spr ...

  3. Unity3D内存优化案例讲解

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

  4. Unity3D 游戏开发之内存优化

    项目的性能优化主要围绕CPU.GPU和内存三大方面进行. 无论是游戏还是VR应用,内存管理都是其研发阶段的重中之重. 然而,在我们测评过的大量项目中,90%以上的项目都存在不同程度的内存使用问题.就目 ...

  5. Unity3d代码及效率优化总结

    1.PC平台的话保持场景中显示的顶点数少于200K~3M,移动设备的话少于10W,一切取决于你的目标GPU与CPU. 2.如果你用U3D自带的SHADER,在表现不差的情况下选择Mobile或Unli ...

  6. U3D内存优化

    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院                                                U3D内存优化   读了Hog关于内存管理文章 ...

  7. Unity内存优化技术测试案例

    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:<手把手教你架构3D游戏引擎>电子工业出版社和<Unity3D实战核心技术详解 ...

  8. Unity堆内存优化

    unity中减少堆内存分配以减少垃圾回收处理:只有局部变量且为值类值的变量是从stack栈中分配内存,其它所有情况都是从heap堆中分配内在.* 缓存获取到的数据.* 频繁被调用的函数中尽量少的分配空 ...

  9. In-Memory:内存优化表的事务处理

    内存优化表(Memory-Optimized Table,简称MOT)使用乐观策略(optimistic approach)实现事务的并发控制,在读取MOT时,使用多行版本化(Multi-Row ve ...

随机推荐

  1. Redis五种数据类型-设置key的过期时间

    1.redis命令客户端 [root@localhost bin]# ./redis-cli 127.0.0.1:6379> #是否运行着 127.0.0.1:6379> ping PON ...

  2. AndroidManifest.xml配置文件详解 (转)

    原文:http://blog.csdn.net/shagoo/article/details/7485958# AndroidManifest.xml配置文件对于Android应用开发来说是非常重要的 ...

  3. centos7 mysql5.7 rpm 安装

    卸载MariaDB CentOS7默认安装MariaDB而不是MySQL,而且yum服务器上也移除了MySQL相关的软件包.因为MariaDB和MySQL可能会冲突,故先卸载MariaDB. 查看已安 ...

  4. UEditor插入视频,Object Iframe等标签被过滤问题处理

    UEditor插入视频由于兼容性问题,需要再处理一个视频代码,但是新版ueditor不支持Objec IFrame标签,所以要加入// xss过滤白名单 名单来源: https://raw.githu ...

  5. javascript编写带阴历的黄历

    最近在做一个黄历的快应用(quickapp),需要涉及到公历转阴历,效果如下: 快应用(https://www.quickapp.cn/): 快应用是基于手机硬件平台的新型应用形态:标准是由主流手机厂 ...

  6. C# 动态加载组件后怎么在开发环境中调试

    动态加载组件 那就是简单的Assembly.Load动态加载dll而以.这网上资料也有不少.基本的思路基本上就是在本地上一个指定目录如[plugs]存在着一堆dll文件.主程序在初始运行时一般会把指定 ...

  7. 无线网络实体图生成工具airgraph-ng

    无线网络实体图生成工具airgraph-ng   airgraph-ng是aircrack-ng套件提供的一个图表生成工具.该工具可以根据airodump工具生成的CSV文件绘制PNG格式的图.绘制的 ...

  8. 五校联考R1 Day2T2 矩阵matrix(容斥)

    题目链接 容易想到容斥,但是很恶心,因为要对行和列都容斥,然后行+列又要容斥.. 于是得到\(O(nm\log)\)的做法. 就有70分了: #include <cstdio> #incl ...

  9. Codeforces.838E.Convex Countour(区间DP)

    题目链接 \(Description\) 给定一个n边凸多边形(保证没有三点共线),求一条经过每个点最多一次的不会相交的路径,使得其长度最大.输出这个长度. \(Solution\) 最长路径应该是尽 ...

  10. BZOJ4275 : [ONTAK2015]Badania naukowe

    设f[i][j]为a[1..i]与b[1..j]的LCS,g[i][j]为a[i..n]与b[j..m]的LCS. 若C为0,则ans=f[n][m]. 否则求出d[i]=a中从i开始往右匹配上c串的 ...