Skip to content

内存与显存

内存与显存控制也是一个重要因素,总结为一点就是管控好各个模块的行为。

对于业务模块来说,无法约定其管控对象或者buffer的具体策略,这里可以谈谈注意的一些方面:

  • 闭包持有的对象:一般对象没有释放,往往会被闭包持有,如发现管理器的列表中已经释放了实例对象,但是内存没有下去,做menmory snap的时候往往会发现它被闭包持有。这要求我们把函数也做为一个对象来管理。这种情况往往发生在事件、定时器等回调函数的绑定中。
  • 编码习惯:写create就写对应的destroy,先写destroy,而不是create出来就去写业务逻辑,业务逻辑又很复杂很费脑细胞,等业务逻辑写完了,destroy的事情也忘记掉了。于此对应的还有定时器的创建和删除、事件的bind和unbind等等。
  • 使用脱离dom树的element:对于imageElement或者canvaElement等,如果创建出来没有挂到dom上,很容易被遗忘,但其内存又无法通过内存快照的比对发现,因为chrome有GPU进程,这个进程也持有了可能上传到GPU上的内存,也就是说imageElement和canvasElment的大量内存是在GPU进程的,而页面的主进程中只是一个壳子。

对于引擎侧的资源(模型、纹理、材质、渲染目标)来说,他们也是有管控策略的

  • 模型和纹理:
    • 内存方面:他们的对象是交给使用方也就是业务侧来把控的,如果它们不被任何渲染对象使用以后也不再使用,那么应该释放。一种简单的方式是把资源对象挂到渲染树上的运行时对象中,然后管控这个运行时对象(如RoyMeshComponent),不再直接对资源进行管理,释放了这个运行时对象,就是释放了其持有的资源。引擎侧还封装了资源管理器,来管控和解决因为多次请求可能形成双份内存资源的问题。
    • 显存方面:显存是引擎内部把控的。挂接到场景树上的运行时对象,获取其中的可渲染对象,在渲染对象进入渲染队列时将其所需的资源从内存上传到显存,如果一个对象因为任何原因(visible为false也好,删除了也好)一段时间没有被绘制,那么其显存资源会被自动清除,当下次再次渲染时,会重新上传到显卡。我们封装了RoyResProvider来解决内存与显存交互的问题。
  • 材质模板与材质实例:
    • 材质模板常驻内存,一共没有几个,一共也没有多大
    • 材质实例,受到业务侧管控。积极释放,或者不持有与渲染对象一起管理。
  • 渲染目标:
    • 高级特性,业务侧全权掌控其生命周期。