美文网首页Cocos2dx游戏开发
1、cocos2d-x学习笔记——内存管理

1、cocos2d-x学习笔记——内存管理

作者: 鱼鸟fly | 来源:发表于2016-04-21 16:39 被阅读65次

    内存管理主要有两种方式,一种是引用计数,还有一种是垃圾回收机制,而cocos2d-x使用的是前者,接下来解释一下引用计数的原理。

    其原理就是在有指针需要引用这个对象的时候将引用计数加1,不需要的时候要减1。当引用计数为0的时候释放内存。

    来看看Node的父类,类Ref。这个类有构造函数、析构函数和四个成员函数,retain()、release()、autorelease()和getReferenceCount(),还有一个成员变量_referenceCount。其他的成员变量和引用计数无关,这里不做讨论。下面来解释这四个成员函数和一个成员变量。

    _referenceCount,用来存储引用的次数。构造函数在创建类的时候将_referenceCount初始化为1。

    retain(),这个函数用于将引用计数加1。如果需要引用这块内存的时候没有加1,则会在使用的时候,可能会遇到使用的这块内存被释放的问题。

    release(),这个函数用于将引用计数减1,当引用计数为0的时候释放这快内存。如果retian后没有调用release,引用计数不会为0,内存不会被释放,造成内存泄漏。

    autorelease(),这个函数将对象放进自动释放池,自动释放池在每次mainLoop()函数的最后会调用clear()将自动释放池里面所有对象的引用计数都减1。这个函数使用在需要延时调用release()函数的指针上(如这块内存地址需要返回,最常见在create函数里面)。

    只要记住这样一条法则就可以了:创建对象后或者调用了retian()一定要调用release(),如果要延迟释放的时候调用autorelease()。

    使用引用计数的时候要注意一点,循环引用。其代码如下
    A.h

    #include <stdio.h>
    
    class B;
    
    class A:public cocos2d::Ref {
       
    public:
        
        A();
        ~A();
        
        void setB(B * b);
        
    private:
        
        B * _b;
        
    };
    

    A.cpp

    #include "A.hpp"
    #include "B.hpp"
    
    A::A():_b(nullptr)
    {
        
    }
    
    A::~A()
    {
        _b->release();
    }
    
    void A::setB(B *b)
    {
        CC_SAFE_RELEASE(_b);
        _b = b;
        CC_SAFE_RETAIN(_b);
    }
    

    B.h

    #include <stdio.h>
    #include "A.hpp"
    
    class B:public cocos2d::Ref {
        
        
    public:
        
        B();
        ~B();
        
        void setA(A * a);
        
    private:
        
        A * _a;
        
    };
    

    B.cpp

    B::B():_a(nullptr)
    {
        
    }
    
    B::~B()
    {
        _a->release();
    }
    
    void B::setA(A *a)
    {
        CC_SAFE_RELEASE(_a);
        _a = a;
        CC_SAFE_RETAIN(_a);
    }
    

    使用时的代码

    A * a = new (std::nothrow)A();
    B * b = new (std::nothrow)B();
    a->setB(b);
    b->setA(a);
    a->release();
    b->release();
    

    在类A里面有个类型为B成员变量_b,在setB(B *b)函数中对_b调用了retain()函数,在析构函数中对_b调用了release()函数。在类B里面有个类型为A的成员变量_a,在setA(A *a)函数中对_a调用了retain()函数。现在创建类A的实例a,类B的实例b,并且a->setB(b);b->setA(a),最后分别对a、b调用一次release()。这样就会造成循环引用,因为a的引用计数为1,b的引用计数也为1,a和b都没有被释放,也不会调用析构函数里面的release()释放a和b。从而造成内存泄漏。这里提供一种方法,根据程序需要将其中一个set函数里面的retain()去掉,也就是弱引用(weak reference)。

    另外,在cocos2d自定义的Vector和Map两个容器类里面,只要是有数据插入就会调用retain函数,有数据删除就会调用release函数。因此,在每次调用create工厂方法后都要将返回值放入到父节点里面或者调用retain方法,不然在下一次调用mainLoop函数的时候就会使用已经释放的内存。

    相关文章

      网友评论

        本文标题:1、cocos2d-x学习笔记——内存管理

        本文链接:https://www.haomeiwen.com/subject/wimtrttx.html