转载请注明: 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的时候删除。这样做不会有内存泄露,也最简单。
    


引用计数的cocos2dx对象内存管理和直接new/delete box2d对象内存管理冲突的解决方法的更多相关文章

  1. Cocos2d-x 3.2编译生成Android程序出错Error running command, return code: 2的解决方法

    用Cocos2d-x 3.2正式版创建项目,结果使用cocos compile -p android编译生成APK程序,结果悲剧了,出现以下错误. Android NDK: Invalid APP_S ...

  2. 关于Cocos2d-x中掉帧导致游戏一卡一卡的网上一些的解决方法

    方法1 掉帧主要是setpostion引起的  因为每一帧每一个精灵都要set一次虽然不知道为什么会这样但是if(poX<1000&&pox>-100){     xx-& ...

  3. iOS内存管理系列之一:对象所有权与引用计数

    当一个所有者(owner,其本身可以是任何一个Objective-C对象)做了以下某个动作时,它拥有对一个对象的所有权(ownership): 1. 创建一个对象.包括使用任何名称中包含“alloc” ...

  4. Objective-C内存管理之引用计数

    初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...

  5. OC基础15:内存管理和自动引用计数

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.什么是ARC? (1).ARC全名为A ...

  6. cocos2D-x 3.5 引擎解析之--引用计数(Ref),自己主动释放池(PoolManager),自己主动释放池管理器( AutoreleasePool)

    #include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. C ...

  7. 初步swift语言学习笔记6(ARC-自己主动引用计数,内存管理)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/31824179 转载请注明出处 假设认为文章对你有所帮助.请通过留言 ...

  8. swift内存管理中的引用计数

    在swift中,每一个对象都有生命周期,当生命周期结束会调用deinit()函数进行释放内存空间. 观察这一段代码: class Person{ var name: String var pet: P ...

  9. iOS内存管理机制解析之MRC手动引用计数机制

    前言: iOS的内存管理机制ARC和MRC是程序猿參加面试基本必问的问题,也是考察一个iOS基本功是 否扎实的关键,这样深入理解内存管理机制的重要性就不言而喻了. iOS内存管理机制发展史 iOS 5 ...

随机推荐

  1. angular项目中使用angular-material2

    Step 1: Install Angular Material and Angular CDK npm install --save @angular/material @angular/cdk n ...

  2. PHP解决并发问题的几种实现

    对于商品抢购等并发场景下,可能会出现超卖的现象,这时就需要解决并发所带来的这些问题了 在PHP语言中并没有原生的提供并发的解决方案,因此就需要借助其他方式来实现并发控制. 方案一:使用文件锁排它锁 f ...

  3. golang之结构体和方法

    结构体的定义 结构体是将零个或者多个任意类型的命令变量组合在一起的聚合数据类型.每个变量都叫做结构体的成员. 其实简单理解,Go语言的结构体struct和其他语言的类class有相等的地位,但是GO语 ...

  4. ios app应用在显示屏幕上改中文名

    1.点击项目名 2.选Build settings 搜索 product name 3.双击,改为需要在手机上显示的应用名

  5. FPGA 17最佳论文导读 ESE: Efficient Speech Recognition Engine with Compressed LSTM on FPGA

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.机器学习技术感兴趣的同学加入. 后面陆续写一些关于神经网络加 ...

  6. ECMA6

    let关键字 用来替代var 的关键字,不能重复定义一个变量 举例: for(var i=0; i<5; i++){      setTimeout(function(){           ...

  7. day1作业二:多级菜单

        作业二:多级菜单 1.三级菜单 2.可以次选择进入各子菜单 3.所需新知识点:列表.字典 4.打印b回到上一层 5.打印q退出循环 流程图如下: readme: (1)存储三级菜单的字典;设置 ...

  8. 小甲鱼Python笔记(类)

    类和对象 类的构造方法 def __init__(): 1 class People: 2 def __init__(self,name): 3 self.name = name 注意:在构造方法中的 ...

  9. email 校验

    email 校验: javascript: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/ java: ^([a- ...

  10. logging记录日志

    日志是一个系统的重要组成部分,用以记录用户操作.系统运行状态和错误信息.日志记录的好坏直接关系到系统出现问题时定位的速度.logging模块Python2.3版本开始成为Python标准库的一部分. ...