« 关于 manual gc 的代码分析 | 返回首页 | 为 lua 封装 C 对象的生存期管理问题 »

关于游戏中资源管理的一些补充

最近在实践中印证了我的一些想法,是关于资源管理的。确认自己的猜想是正确的总是件开心的事情。

先简单回顾一下以前写的几篇东西:

资源的内存管理及多线程预读

这不是最早的思路,但是是我能找到的最早在 blog 上公开并实际实现的思路。里面提到的部分东西,尤其是多线程设计部分,后来都一一被换掉,理由是过于复杂并实际上没能达到要求。或是细节上很难有 stable 的实现。

胡思乱想续

经过一些思考,以及经历了许多实践后。对上面的东西,一部分做了肯定,一部分做了否定。肯定的是,资源管理的大策略是对的:那就是和其它部分正交化,尤其是要独立于游戏逻辑之外。生存期不应和游戏逻辑耦合。

重构

到目前最后一次在 blog 上记录思考和资源管理相关的问题。认清的最重要一点就是:

至于多线程预读的问题,资源模块已经可以了解资源数据文件间的关联信息。简单的开一条线程 touch 那些未来可能读到的文件即可。把预读和缓冲的工作交给 OS ,这应该是一个简洁有效的设计。并不需要太多顾虑线程安全的问题。

那么今天想说什么?

由于我们的一个疏忽,在最近的一个小程序中,把资源管理模块的调节阀值设到了 6M 内存,也就是说,只要超过 6M 数据,资源管理模块就会自动的清理一些它认为可以清理的数据。

原来我们的计划并不是这么小,当时是为了想尽快发现一些 bug ,让资源管理模块工作的更频繁而设小的。

但是,我们得到了一个惊异的结果。跑了一个很复杂游戏场景的 client ,从 os 的管理器中观察,居然一直都保持在 36M 内存的占用。一开始,大家还都不敢相信。因为 3d engine 本身会固定吃掉大约 30M 内存。而这个 client 却跑了很丰富的游戏场景。最后确认后,合理的解释是,的确 6M 资源数据区就够用了。(这方面 3d 游戏比 2d 游戏更节省内存)

不过为什么 client 依旧跑的很流畅呢?应该是 os 的 cache 机制做的很不错。而那台机器安装了 2G 的内存条。其实,并没有发生太多的硬盘读操作。

我们把 6M 的阀值调到了 128M ,client 迅速的吃满了分配给它的空间,但是 client 的流畅度并没有太大的提高。

反而,如果多开几个类似的程序,还会相互争抢内存。

有了这个数据做基础,前几天写的 关于地图编辑器的一些想法 或许会更加实用。事实上,上面谈到的 client 正是我们临时做的一个符合 editor 协议的观察器(所谓临时,是我们一个程序员花了一天时间,按照协议文档,写的个小程序。注:只是协议文档,我们只规定了通讯协议,还没做成内部通用的 SDK 库)。操作者可以通过连入 editor server 漫游正在编辑的游戏场景,甚至可以实时的观察到别人的编辑更新。

按我的设想,如果美术人员想在编辑时,同时监控场景全貌,或是想从另外一个角度观察他的编辑区。只需要简单的启动一个新的观察器,调整到合适的角度,挂在屏幕一角即可。

更小的内存(以及 CPU )占用,使得这件事情变的便捷。 btw, 我们的编辑器目前所有资源都从网络下载,在百兆 LAN 上也工作的非常流畅。方便了很多人一起工作。

editor server 保存了美术人员左右的工作流程,等游戏做完的时候,我想我会制作一段 video ,展示整个游戏虚拟世界从无到有的过程。

Comments

"经过一些思考,以及经历了许多实践后。对上面的东西,一部分做了肯定,一部分做了否定。" 很想知道,否定的那一部分是什么?
"1. 如果Client占用那么少的内存,是否操作系统需要很多的内存来缓存磁盘文件?...例如空间切割树,如果不能缓存,那么重建空间切割树是否需要大量的时间? " 呵呵,这位老兄说话真的够委婉...学习下.
考虑内存占用的时候需要也显示虚拟内存占用比较合理. 个人很反感m$的filecache,很可能把物理内存吃光搞到系统巨慢(做个大文件复制就知道了),所以后来读写都改了unbuffer模式并自己管理cache.
我有几个疑问: 1. 如果Client占用那么少的内存,是否操作系统需要很多的内存来缓存磁盘文件? 2. 是否所有Client访问的资源都可以被操作系统进行缓存,例如空间切割树,如果不能缓存,那么重建空间切割树是否需要大量的时间? 3. 如果引擎这样设计,资源之间的依赖关系就变得十分的重要,而是否所有的资源依赖关系都可以进行预处理呢?如果不能,操作系统缓存机制是否无法快速命中引擎请求的资源呢?那样是否会卡?
我的一次尝试:比较一次读文件和memcopy效率,意外的发现读文件竟高达memcopy速度的3/4左右。。。
这篇文章看得我热血沸腾,程序员的职责就是改变生活,生活真美好,我想看整个游戏虚拟世界从无到有的过程的那个video
并非因为复杂把功能砍掉,而是找到更简单的方法把目的达到。 在这里的策略就是: 在资源文件中自描述资源和资源间的引用关系。 开一条线程依靠这些相互关系提前 touch 相关文件。这条线程是独立工作,并不往工作线程注入任何实际数据。
哈,我还从来没听说因为复杂而要把功能砍掉的。 如果浏览器的开发者跟用户说:异步资源载入太复杂了,所以我们的浏览器必须等网页全部下载完了才能显示出来。估计会被人笑死。 另外,实在是没觉得异步载入有什么复杂,当然前提是需要这个功能,如果没有异步的需求,那就没什么好说了。这个问题我们可以私下再讨论。
云风兄 居然一直都报纸在 36M 内存的占用 此处的报纸应为保持吧?
editor server 保存了美术人员左右的工作流程,等游戏做完的时候,我想我会制作一段 video ,展示整个游戏虚拟世界从无到有的过程。 听着都有点热血沸腾的感觉了。让炒作来的更猛烈些吧!:D
如果我没有理解错误的话,应该是『调节阈值』。 你们的目标是把KISS做到无以复加,佩服……
"你很可能是释放了内存而没有释放掉显卡里的resource handle。" 不要乱猜的啦, 那是绝对不可能的。 KISS 的原则并不是表面工夫。所谓复杂不复杂,并不是看能不能实现决定的。 所谓多线程资源载入,01 年的大话 client 里就实现并很好的工作到现在。但是能不能正常工作,和是否复杂是两件事情。
另外多线程异步资源载入也不是什么困难的事情,很多年前我们就实现了,一直用的好好的,完全没觉得有什么复杂, 新一代的DX11貌似对异步资源载入提供了一些原生的支持,那样性能就更好了。
我估计云风是犯了低级错误了。这个道理其实很简单,3D程序的资源都是顶点数据和纹理数据,每次从磁盘读取到内存以后还需要upload到显卡里,你很可能是释放了内存而没有释放掉显卡里的resource handle。 相反,如果你频繁的分配释放纹理资源的话渲染会非常的慢,因为一般情况下GPU跟CPU是并行工作的,调用3D API的时候CPU只是往命令缓冲里提交一个渲染指令,如果此时需要分配释放资源,则CPU必须等待GPU把渲染缓冲排空了才行。

Post a comment

非这个主题相关的留言请到:留言本