我所理解的Cocos2d-x Cocos2d-x 内存管理机制

C++内存管理

C++显式堆内存管理

性能上有一定优势,但有如下缺点:

  • 野指针:指针指向的内容已经被释放,但是其他指针还可能指向它。
  • 重复释放:重复释放一个已经释放的内存单元,或者释放一个野指针,都会导致C++运行时错误。
  • 内存泄露:不再被使用的内存单元如果不被释放,就会一直占用内存单元。

C++11智能指针

主要有如下三种:

  • unique_ptr:不能与其他智能指针共享所指对象的内存。一旦转移成功,就不能使用原来的指针,否则会导致运行时错误。
  • shared_ptr:共享同一堆分配对象的内存,它在实现上采用引用指针。只有引用计数为零时,才会真正释放占有的堆内存。
  • weak_ptr:指向shared_ptr指针分配的对象内存,但不拥有该内存。我们可以使用其lock成员来访问其指向内存的一个shared_ptr对象,当其所指向的内存无效时,返回空值(nullptr)。weak_ptr指针通常可以用来验证shared_ptr指针的有效性。

为什么Cocos2d-x不使用智能指针

有如下理由:

  1. 智能指针有较大的性能损失。
  2. 它需要程序员显示地声明智能指针。
  3. 在需要引用的地方,一般应该使用weak_ptr指针,否则在Node被移除的时候还要手动减持shared_ptr指针的引用计数。

程序员每天都面对代码,他们需要更自然的内存管理方式,就像语言自身的特性一样,甚至几乎察觉不到背后的机制。

C++垃圾回收机制

  • 基于引用计数:当对象被引用的次数变为零时,该对象即被视作垃圾而被回收。
  • 基于跟踪处理:先产生跟踪对象的关系图,再进行垃圾回收。

不管采用哪种方式,垃圾回收机制都可以使内存管理变得更自然。

Cocos2d-x内存管理

引用计数

Cocos2d-x中的所有对象几乎都继承自Ref基类,Ref基类的主要职责就是对对象进行引用计数管理。

  • 当一个对象使用new运算符分配内存时,引用计数为1。
  • 调用retain()方法会增加其引用计数。
  • 调用release()方法会减少其引用计数。并且在其引用计数为0时自动调用delete运算符删除对象并释放内存。

Ref的引用计数并不是线程安全的。在多线程中,我们需要通过处理互斥锁来保证线程的安全。

自动回收池(AutoreleasePool)

Cocos2d-x在每一帧结束的时候清理当前AutoreleasePool中的对象,因此可以使用autorelease()方法来声明一个对象指针加入AutoreleasePool。

为了化简这种声明,Cocos2d-x使用静态的create()方法来调用加入AutoreleasePool。同时,自定义的UI元素也应该遵循这样的风格。

AutoreleasePool队列

对于一些游戏对象而言,一帧的生命周期有些长。我们需要能够自定义AutoreleasePool的生命周长。AutoreleasePool在构造函数中将自身指针添加到PoolManager的AutoreleasePool队列中,并在析构函数中从队列中移除自己。通过在函数开头定义AutoreleasePool对象,就能控制Cocos2d-x中的autorelease对象的声明周期了。

不要动态分配AutoreleasePool对象,而始终使用自动变量。

Cocos2d-x中的智能指针

Cocos2d-x 3.1 引入了智能指针RefPtr<T>,是基于RAII实现的。

  1. 构造函数
    RefPtr需要依赖Ref的引用计数来管理内存,因此所有类型T必须是Ref类型。

    • 对于使用左值作为构造函数的参数,会使得引用计数加1。
    • 而使用右值作为构造函数的参数,不会使得引用计数加1。而是使用了移动复制构造函数,将其对应的内存占用转移过来。
  2. 赋值操作符

    • 对于使用左值来赋值,会使得引用计数加1。
    • 而使用右值来赋值,不会使得引用计数加1。而是使用了移动复制构造函数,将其对应的内存占用转移过来。不过,有一点不同的是会释放之前旧的资源的引用计数。
  3. 弱引用赋值

    RefPtr通过提供一个weakAssign()方法来实现弱引用。
    但是在析构的时候,依然会release()一次。
    有什么用呢?示例如下:

    void a()  
    {  
        RefPtr<Texture2D> l;  
        l.weakAssign(new Texture2D);  
        // -- doSomething  
    
        return;  
    }

    在函数中并没有delete,但是依旧不会造成内存泄露。

  4. 析构函数:对_ptr进行safe delete。

  5. 重载了“*”和“->”操作符,使得其能够直接访问资源的地址。另外也可以通过get()方法来访问资源的地址。

  6. RefPtr也重载了bool()操作符,使我们可以直接判断其有效性。

  1. Cocos2d-x自动回收池和智能指针该用谁?
    作者的建议是,所有的UI元素都需要使用autorelease来管理,而游戏中的数据则使用智能智能RefPtr来管理。
  2. RefPtr的缺陷
    1. 可以从外部修改引用计数。
    2. 虽然RefPtr提供了一种弱引用,不对其进行引用计数增加,但仍然表现为一个强类型智能指针的行为,它仍然可以对其资源进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值