ejoy2d sprite pack 的空间优化
在 ejoy2d 里,我将 sprite 的结构信息储存在一组叫 sprite pack 的结构中。其中包括动画的 frame 数据,sprite 由若干部分组成,每个部分的变换矩阵,对应贴图的编码和坐标等等。
通常这些数据不会太大,所以我建议一次加载到内存就不再删除。而动态生成的 sprite 对象则直接引用这些数据,不必做引用计数。这些数据之间的交叉引用(可以像搭积木一样用很多部件构成复杂的 sprite )也不需要额外记录。但如果保存了大量的动画信息,或 sprite 是由非常多的小部件构成,数据量也可能非常可观。
在我们的 心动庄园 里,达到了数十 M 内存之多。前几天同事提到这个问题,我便动手做了一点简单的优化,居然省出了几十兆内存。
其实方法很简单。在 64bit 平台上,我将 sprite pack 结构中的指针都改成了一个 32bit 的相对 pack 头的偏移量。
在设计之初,我就是把整个 sprite pack 存放在连续单个内存块上的。为之做了一个非常简单的 bump allocator :资源打包的时候,统计整个要用的内存数量,然后在包加载时就分配出来,然后每个小对象都紧贴在一起保存。这样可以节省下大量小内存块的头,并将常规内存管理中可能出现的内存碎片率减少到零。
由于原本就是连续内存块,把指针更替成偏移量不需要修改太多代码 。
把指针体积减少一半后,数据结构对齐也会变得更紧凑,在我们公司三个项目实际比对下来后,发现 sprite pack 占内存量大约可以减少 40% 。
做次修改后,还获得了一个额外的好处。sprite pack 在内存中已经完全不包含指针,也就是说可以随意在内存中移动了,变得和地址无关。
我们可以在打包时直接把 sprite pack 的内存块直接 dump 到文件,加载时可以绕过 import 过程。想来可以快上不少(还没有测试)。即使不能提高太多性能,我们的资源加载过程会变得和资源文件大小严格相关,也就是说,可以通过资源文件体积来准确预测加载时间,可以实现一个非常匀速准确的 loading 条了。我想这对用户体验来说,是个不错的改善。
Comments
建议你们生成资源时对数据在可以直接解析的情况下去掉冗余数据并载入到内存里可以直接解析。生成到硬盘上的大小就是你们运行中会费的内存大小。一目了然。自己规定一个内存占用上限,如果感觉小就一次性加载,感觉大就对数据进行调整,调整不了。就不能一次性载入内存了.得想动态的方法了
Posted by: Anonymous | (2) February 4, 2016 12:40 AM
没想到这个地方居然能让你们费掉几十M内存。一般费内存是这种小结构体分配的次数太多会这样。我现在就是一次性读取到内存里结构都完整了。不需要解析。io 10m大小的文件一般几十毫秒就ok,逻辑上静态的数据就都应该这样整。
Posted by: Anonymous | (1) February 4, 2016 12:32 AM