第四十九章 引擎1.0倒计时
    十二月二十七日,沈连河在引擎组的进度板上贴了一张红色便签。

    便签上写着“1.0 RC1”,后面跟了一个日期,十二月三十一日。这是九命引擎一点零版本的第一个发布候选版,需要在年底前完成代码冻结。距离目标还有四天。

    引擎组的四个新人围在进度板前,看着那张红色便签,没有人说话。沈连河站在他们身后,手里拿着笔记本,翻到今天的那一页。上面列着十五项待完成的任务,每项后面都标注了负责人和预计耗时。他用笔划掉了前三项,然后抬起头。

    “今天,内存泄漏。明天,性能回归测试。后天,文档。大后天,发布。”

    四天,十五项任务。平均每人每天将近一项。没有人抱怨。一个新来的工程师举手,问了一个问题。

    “沈哥,内存泄漏那个bug,我之前看了两天没找到原因。能不能让林哥帮忙看看。”

    沈连河点了点头。“我问他。”

    他走到林子轩工位前,把笔记本翻到内存泄漏那一页,放在桌上。林子轩正在调试《共火》的一个网络同步的边缘案例,屏幕上全是十六进制的内存地址。他扫了一眼笔记本上的问题描述,把棒棒糖从左边挪到右边。

    “哪个模块。”

    “资源加载。纹理卸载后,内存没有完全释放。定位到是引用计数的问题,但不知道哪里多了一次引用。”

    林子轩把屏幕上的调试器关了,打开资源加载模块的代码。他翻了大概三分钟,停在了一个函数上。函数名叫UnloadTexture,里面有一行注释是沈连河写的。“此处减少引用计数,若归零则释放内存。”

    林子轩在那行注释下面加了一行新注释。“调用此函数前,某处多了一次AddRef。检查第487行。”

    沈连河翻到第四百八十七行。那是一段异步加载的回调函数,在纹理加载完成后,对同一个纹理对象调用了两次AddRef。一次是显式调用,一次是作为回调参数隐式传递。所以UnloadTexture只减少了一次引用,引用计数永远到不了零,内存永远不会释放。

    他把这行代码改成了单次引用。重新编译,跑内存测试。运行了三个小时,内存占用曲线平稳,没有泄漏。沈连河在笔记本上划掉了第一项任务,然后在旁边写了一个数字。还剩十四项。

    许知意路过的时候看到引擎组所有人都在埋头写代码,键盘声连成一片,像下雨。她没打扰,放了一杯水在沈连河桌上,杯底压了一张便签,上面画了一个猫爪。

    十二月二十八日,性能回归测试。沈连河写了一套自动化脚本,跑了两百多个基准测试场景,对比零点九版本和一点零候选版的性能数据。渲染性能平均提升百分之十二,物理模拟提升百分之八,资源加载速度提升百分之二十五。所有指标都是绿色,没有性能回退。

    但他发现了一个新问题。在低配置机器上,集成显卡加两G内存的那种,一点零候选版的启动速度比零点九慢了将近三秒。不是引擎变慢了,是功能变多了。更多的功能意味着更多的初始化代码,更多的初始化代码意味着更长的启动时间。这个问题的本质不是bug,是设计决策。要不要为了低配用户的启动体验,砍掉一些非核心功能。

    沈连河把这个问题带到了晚间的技术讨论会上。会议室里坐了五个人,林子轩、沈连河、两个引擎组的新人,还有孟缘。孟缘是被沈连河叫来的,他说这是个取舍问题,需要做决定的人在场。

    沈连河把数据投到屏幕上。低配机器的启动时间,零点九是八秒,一点零候选版是十一秒。慢了百分之三十七点五。原因在于一点零新增的着色器预编译和资源预加载机制,这两项功能在高配机器上几乎感觉不到延迟,但在低配机器上,CPU和硬盘的速度成了瓶颈。

    林子轩把棒棒糖从嘴里拿出来。“预编译可以改成懒加载。第一次用到的时候再编译,启动时间能回到九秒以内。代价是游戏过程中第一次使用某个特效时会卡一下。”

    沈连河摇了摇头。“那个卡顿用户更受不了。启动慢一次,用户可能骂一句。游戏里卡一下,用户可能直接关掉。”

    两个方案都有问题。会议室安静了大概半分钟。孟缘开口了。

    “低配用户的比例是多少。”

    沈连河翻出一份数据。“橘猫平台上,集成显卡用户占比大概百分之六十五。其中内存小于等于两G的,大概百分之三十。按这个比例算,大约百分之二十的用户会受到启动时间的影响。”

    “两百万用户。”孟缘的手指在桌面上敲了一下,“四十万人。”

    他沉默了几秒。“能不能做一个开关。自动检测硬件配置,低配机器用懒加载,高配机器用预加载。两套方案根据设备自动切换,用户不需要知道区别。”

    林子轩把棒棒糖重新塞进嘴里。沈连河翻开笔记本,在第十四项任务后面加了一项。“自动配置检

本章未完,请点击下一页继续阅读>>