我们公司的一个 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. 从零开始自己搭建复杂网络(以Tensorflow为例)

    从零开始自己搭建复杂网络(以MobileNetV2为例) tensorflow经过这几年的发展,已经成长为最大的神经网络框架.而mobileNetV2在经过Xception的实践与深度可分离卷积的应用 ...

  2. 兼容IE FF 获取鼠标位置

    由于Firefox和IE等浏览器之间对js解释的方式不一样,firefox下面获取鼠标位置不能够直接使用clientX来获取.网上说的一般都是触发mousemove事件才行.我这里有两段代码,思路都一 ...

  3. 移动端经常出现的兼容问题,谈谈移动端应用或者wap站的一些优化技巧和心得

    移动端经常出现的兼容问题,谈谈移动端应用或者wap站的一些优化技巧和心得 1.        安卓浏览器看背景图片,有些设备会模糊. 因为手机分辨率太小,如果按照分辨率来显示网页,字会非常小,安卓手机 ...

  4. ERP渠道活动管理(二十六)

    设计意义: 渠道活动的方式方法多种多样.不过,大至可分为销售型促销与市场型促销(一般来说,销售型促销以完成销售额为唯一目的,以奖励返点为唯一手段,以增大经销商库存为最终结果,短期行为明显.而市场型促销 ...

  5. 主动学习(Active Learning)

    主动学习简介 在某些情况下,没有类标签的数据相当丰富而有类标签的数据相当稀少,并且人工对数据进行标记的成本又相当高昂.在这种情况下,我们可以让学习算法主动地提出要对哪些数据进行标注,之后我们要将这些数 ...

  6. 000 Html基本标签与案例

    在CSS之前,需要先介绍一下HTML的常用标签. 1.html与css的关系 2.程序 <!DOCTYPE HTML> <html> <head> <meta ...

  7. ajax跨域请求Flask后台

    ajax中使用jsonp方式实现跨域 headers: {'Cookie' : document.cookie } #携带cookie xhrFields: { withCredentials: tr ...

  8. 使用Synchronized块同步变量

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特定的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  9. 利用cve-2017-11882的一次渗透测试

    利用工具:https://github.com/Ridter/CVE-2017-11882/ 影响版本: office 2003 office 2007 office 2010 office 2013 ...

  10. 慢查询日志分析工具之mysqldumpslow

    使用方法: 在 windows 下可以在mysql/bin目录下可以找到 mysqldumpslow.pl 文件,是一个 perl 格式的文件,如下图: 这种格式的文件在windows下是不能直接执行 ...