cocos2d-x的内存管理问题

    关于cocos2d-x的内存管理有个疑惑,想跟大大们讨论。
    现在的内存管理是借助类似objc的引用计数机制完成的,需要手动处理的retain和release比较多。在实际使用终发现retain和release的时机大多是有规律可循的,基本对应了对象的生成和消亡两个时间。那么是不是可以将管理自动化呢?分别复杂程度由小到大,能想到的是三个解决方案:
  1. 工厂方法
    在创建对象时完全使用node的工厂方法,这样隐含的autorelease已经完成了引用释放,引擎api操作(addChild等)也会作适当的管理;那么唯一需要考虑的,是自定义对象中以成员变量方式引用的变量,需要处理retain release事项。
    潜在的隐患是对autoreleasePool造成过大压力,毕竟那也是一个容器,也有消耗,但是集中触发的delete也许能挽回部分性能。

  2. 智能指针
    boost提供了非常强大的shared_ptr,用其代替一般指针使用,可自动管理内存释放问题。由于shared_ptr的引用计数到0时是直接触发delete的,所以需要对其改造为触发一个release。这样由成员变量产生的内存管理问题也可以妥善解决。
    潜在的隐患是两套内存管理并存可能引起更大的混乱。另一个是普通指针和智能指针间的相互转换,尽管可以通过重载等于号消除掉显式的reset,但另一个比较麻烦的是引擎的api是指针式的,调用函数时必须用pointer.get()的方式解开包装。

  3. 对象体系改造
    直接对CCObject的内存管理机制改造。现在的CCObject最大的功能应该是提供一个内存管理的接口,如果利用好c++的运算符重载,完全可以在赋值时完成机械的“先release后retain”操作。但是指针的运算符是无法重载的,也就要求CCObject放弃现在的指针式引用,转变为类似java和c#的无指针对象引用。

    在实际使用中内存管理确实是个很头疼的问题,一直在思考如何改善,就有了以上的想法。值得说明的是,效率最高的必然是纯人工的new delete,而智能指针和对象体系改造本质上应该和retain/release的管理方式是类似的,计算消耗的差距不会太大甚至应该更优。考虑到与cocos2d-iphone版引擎的兼容,cocos2d-x很可能不会去掉retain / release的特性,所以在此分享下我的思路,期待大大们给出解决方案啊~~~

我以前搞tcpmp播放器的时候,纯C语言写的,里面也是同样采用了手动引用计数的方式来管理内存。所以cocos2d-x毫不犹豫地做了引用计数+半手动管理了。想用工厂模式的话其实也不难,自己写个宏就可以了;智能指针我一直不喜欢,stl里面的智能指针也没做好很少人用,另一方面智能指针势必引入C++模版,我们是尽量减少模版、操作符重载和new/delete关键字重载等这些C++高级功能,一方面降低非C++程序员转过来使用的学习门槛,另一方面最重要的是方便lua/javascript绑定。

其实你觉得麻烦的这些问题,在绑好脚本之后,在脚本层就全部解决了,脚本层接口不会再有retain/release这些东西了。

— Begin quote from ____

walzer 发表于 2012-4-25 12:07 url

我以前搞tcpmp播放器的时候,纯C语言写的,里面也是同样采用了手动引用计数的方式来管理内存。所以cocos2d- …

— End quote

感觉改造下对象体系的话,c++用起来跟js差异不大,js的很多特性在c++11里都有了对应的支持,不知道有没有考虑过直接在c++层给一个脚本化的版本?可能在兼顾跨平台特性上会比较差,但是相对的也更好的提高了性能。

用js其实是两方面考虑

  1. Zynga的js程序员多,所以Riq在那边选脚本支持的时候被要求选JS
  2. JS可以和html5打通。

C++的高级功能还是少用为妙,stl我们也是用着很基础的类,你说得对,跨平台性会受影响,

恩。。才刚开始接触。提前了解这点

今天突然想起来一个解法,不妨设置一个holder结构体,在结构体的构造和析构里retain和release,这样函数范围内的内存管理、对象声明周期内的对象管理都可以通过声明一个holder来完成,不再需要考虑release的时机。配合autorelease的话,基本可以解决大多数内存管理场景了吧?

— Begin quote from ____

LittleDing 发表于 2014-1-4 06:01 url

今天突然想起来一个解法,不妨设置一个holder结构体,在结构体的构造和析构里retain和release,这样函数范 …

— End quote

其实更赞同自己来管理内存,C/C++本身就是门信任程序员的语言,而在引擎这一层又被限制了感觉堵得慌。而且其他语言的不一定要用这个版本的cc2d。以上为个人看法。

我更喜欢手动 new/delete,这样心里有数,引擎里没有用内存池,让我有点儿差异,我想至少也不能让 new/delete 到处横飞啊,以后查内存泄露估计是个麻烦事情。

最近用boost的对象池包装了一个可以在cocos2d-x中使用的对象池,自己初步测试通过,效率大约为系统new的1/4。主要的使用接口如下:

CCSprite *sp = MTPoolManager::sharedManager()->getObject(sp);

不需要初始化和生成,以定时器形式每帧自动处理对象回收。
从对象池获得的对象依然需要遵循cocos2d-x的内存管理守则。

附件是源代码,求各位大大指导啊。

424

值得学习啊…我得持续关注

我以前搞tcpmp播放器的时候,纯C语言写的,里面也是同样采用了手动引用计数的方式来管理内存。所以cocos2d-x毫不犹豫地做了引用计数+半手动管理了。想用工厂模式的话其实也不难,自己写个宏就可以了;智能指针我一直不喜欢,stl里面的智能指针也没做好很少人用,另一方面智能指针势必引入C++模版,我们是尽量减少模版、操作符重载和new/delete关键字重载等这些C++高级功能,一方面降低非C++程序员转过来使用的学习门槛,另一方面最重要的是方便lua/javascript绑定。

其实你觉得麻烦的这些问题,在绑好脚本之后,在脚本层就全部解决了,脚本层接口不会再有retain/release这些东西了。

用js其实是两方面考虑

  1. Zynga的js程序员多,所以Riq在那边选脚本支持的时候被要求选JS
  2. JS可以和html5打通。

C++的高级功能还是少用为妙,stl我们也是用着很基础的类,你说得对,跨平台性会受影响,

恩。。才刚开始接触。提前了解这点

— Begin quote from ____

LittleDing 发表于 2014-1-4 06:01 url

今天突然想起来一个解法,不妨设置一个holder结构体,在结构体的构造和析构里retain和release,这样函数范 …

— End quote

其实更赞同自己来管理内存,C/C++本身就是门信任程序员的语言,而在引擎这一层又被限制了感觉堵得慌。而且其他语言的不一定要用这个版本的cc2d。以上为个人看法。

怎么没看到8楼的代码连接呢?