首先,我简单阐述一下现在 Luabinding 针对 C++ 对象的内存管理机制。
当在 Lua 里创建一个 C++ 对象时,这个 C++ 对象的指针会被包装为一个 Lua 值放入 Lua 虚拟机中。
- 对于 Lua 来说,C++ 对象占用的内存就是一个指针的大小(通常只有几十字节);
- C++ 对象实际占用的内存 Lua 虚拟机无法得知。
由于 cocos 的 C++ 对象都使用引用计数和自动释放机制,所以可能出现一个 C++ 对象正在被 Lua 使用时却已经自动删除的情况。要避免这个问题,最简单的做法:
- 对于图像、动画等对象,都在用到的时候才创建;
- 创建后立即加入场景,避免这些 C++ 对象被自动释放。
有些从 C++ 转过来的开发者,还是习惯使用 retain() 来保持 C++ 对象,然后再不需要的时候 release()。
而这种编码习惯其实是不符合 Lua 风格的。
目前有一种修改方式,就是让传入 Lua 虚拟机的 C++ 对象不再自动释放。
而是只有在 Lua 虚拟机做 GC(垃圾回收)的时候才会释放那些 C++ 对象。
但我个人认为这种机制会带来一些严重问题:
1. 很多 C++ 对象之间存在复杂的引用关系。只要其中一个 C++ 对象在 Lua 里使用过,那么所有和这个 C++ 对象存在依赖关系的对象都无法释放。只有等到 lua gc 时才能释放。
2. Lua VM 触发 gc 的时机是根据 lua vm 内存分配来决定的。lua vm 并不知道 C++ 对象占用了多少内存。所以可能出现某个 C++ 对象占用了不少内存,但 lua vm 迟迟不触发 gc 的问题。
3. 在网络化 app 里,第二个问题带来的影响是致命的。比如 http 请求每一次的请求都是一个新的 C++ 对象,而请求结果都会保存在 c++ 对象里。只要不做 lua gc,这些 c++ 对象就会堆积起来,占用大量内存。
4. gc 会导致明显的卡顿,开发者不可能在场景中频繁做 gc。所以游戏的内存占用会持续增加。
请大家各抒己见。
