zoukankan      html  css  js  c++  java
  • 引用计数的cocos2dx对象内存管理和直接new/delete box2d对象内存管理冲突的解决方法

    转载请注明: http://blog.csdn.net/herm_lib/article/details/9316601

    项目中用到了cocos2dx和box2d,cocos2dx的内存是基于引用计数的,新建的内存一般加到一个自动的内存回收池中;而box2d的对象,是直接new/delete。

    基于引用计数的对象和基于new/delete对象生命周期的结束是不一样的,前者有时比后者延后一帧(或者一个逻辑循环)才被删除。看一下实际遇到问题的代码。


    class GameLayer : public cocos2d::CCLayer
    {
    public:
        GameLayer();
        ~GameLayer();
    
        static GameLayer* create();
    private:
        virtual void onEnter();
    private:
    //    static b2World* m_phyWorld;
        b2World* m_phyWorld;
    };
    
    // b2World* GameLayer::m_phyWorld = nullptr;
    
    GameLayer::GameLayer()
    {
        m_phyWorld = nullptr;
    }
    
    GameLayer::~GameLayer()
    {
        delete m_phyWorld;
    }
    
    GameLayer* GameLayer::create()
    {
        GameLayer* layer = new GameLayer;
        layer->autorelease();
    
        return layer;
    }
    
    void GameLayer::onEnter()
    {
        // 删除上一次进关卡生成的物理对象
    //    delete m_phyWorld;
    
        m_phyWorld = new b2World(b2Vec2(0.0f, -10.0f));
        MonsterSprite* monsterSprite = Monster::create(m_phyWorld);
        addChild(monsterSprite);
    
        CCLayer::onEnter();
    }

    GameLayer里生成一个b2World对象,同时也生成一个MonsterSprite 基于引用计数的对象,MonsterSprite是放到autorelease pool里,当GameLayer析构时removeChild, monster会被自动删除。再来看一下Monster做了什么。

    class MonsterSprite : public cocos2d::CCSprite
    {
    private:
        b2World* m_phyWorld;
        b2Body* m_phyBody;
    };
    
    MonsterSprite* MonsterSprite::create(b2World* phyWorld)
    {
        MonsterSprite* monsterSprite = new MonsterSprite(phyWorld);
        MonsterSprite->autorelease();
    
        return MonsterSprite;
    }
    
    MonsterSprite::MonsterSprite(b2World* phyWorld)
    {
        m_phyWorld = phyWorld;
        m_phyBody = phyWorld->CreateBody(...);
    }
    
    MonsterSprite::~MonsterSprite()
    {
        m_phyWorld->DestoryBody(m_phyBody);
    }

    MonsterSprite是一个cocos2d对象,他回创建b2Body, 在析构的时候,将这个body从b2World中删除。
    代码看上去很清晰,貌似很正常。但跑起来,一般情况下,程序会在MonsterSprite::~MonsterSprite()的地方崩溃。我们分析一下,过程。
    [1] 场景切换或者程序退出,GameLayer::~GameLayer()执行,这时候注意看delete m_phyWorld, b2World对象被删除;
    [2] 执行CCLayer::~CCLayer(),  所有子节点被removeChild, MonsterSprite也被removeChild, MonsterSprite引用计数变为1了;
    [3] 程序跑到下一帧,MonsterSprite被release, 执行MonsterSprite::~MonsterSprite,
             m_phyWorld->DestoryBody(m_phyBody);                   
          这个时候,m_phyWorld在上一帧就被删除了。
    这种不同的内存管理方式,导致两个对象生命周期结束不一致。我想到了三种解决办法:
    [1] 封装一下b2World,让的他内存管理方式和cocos2dx对象一致。
    [2] MonsterSprite* monsterSprite = new MonsterSprite(phyWorld); 的时候,把monsterSprite保存起来,在GameLayer::~GameLayer()中,手动把monsterSprite中的b2Body      清除,不要等到析构的时候删除。
    [3] 请看代码注释的地方,把b2World的生命周期拉长,GameLayer退出的时候,不删除;再次进入GameLayer的时候删除。这样做不会有内存泄露,也最简单。
        


  • 相关阅读:
    关于 token
    windows 使用 virtualbox,搭建 minikube 环境
    kafka 和 rocketMQ 的数据存储
    分享周鸿祎的《如何建立一个“铁打的营盘”》
    How to configue session timeout in Hive
    毕业十年纪念
    常用排序算法
    [异常处理]class kafka.common.UnknownTopicOrPartitionException (kafka.server.ReplicaFetcherThread)
    线程的几个状态
    星型模式
  • 原文地址:https://www.cnblogs.com/snake-hand/p/3188611.html
Copyright © 2011-2022 走看看