位置: 编程技术 - 正文

自动释放池是吗,是否可以这样模仿,超简单,嘿嘿(自动释放池原理,本质)

编辑:rootadmin

推荐整理分享自动释放池是吗,是否可以这样模仿,超简单,嘿嘿(自动释放池原理,本质),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:自动释放什么意思,自动释放池原理,本质,ios自动释放池的使用,自动释放装置,自动释放池的工作原理,自动释放池什么时候释放,自动释放池什么时候释放,自动释放池原理,本质,内容如对您有帮助,希望把文章链接给更多的朋友!

喵聊几&#;cocos2dx3.2引擎关于自动释放池里面的源码,感觉也不过如此,不知是否理解正确,这篇文章也许不正确,但完全是出于个人的理解,我可不负什么责任的。

对于自动释放池的定义,我不懂,具体还是百度下吧,以我的理解就是采用的是一种引用计数的机制,实现对同一个对象的操作多个指针的引用,然后将这个对象放到自动释放池里面,在cocos2dx3.2绘制场景的时候,遍历自动释放池里面的对象,一旦发现引用计数为1的时候就将其释放掉,为的是减少内存,提高资源利用率。哎,这表达行不行,不清楚啦。

那么什么是引用计数机制呢,怎么说呢,举个例子吧:

#include<iostream>

using namespace std;

#define CCLOG(strFormat, value) printf(strFormat, value) // 暂时用这个宏模仿cocos2dx3.2里面得日志打印

class Ref

{

public:

Ref():_reference(1) {}//这里给引用计数初始化1,这是仿照cocos2dx3.2引擎里面得初始化

virtual ~Ref(){}

void showMsgRef(){CCLOG("This is a Ref class, and its _reference:%dn",_reference);}

void retain(){&#;&#;_reference;} // 引用计数+1

private:

int _reference ; // 引用计数

};

好了,然后我们在main函数使用它,让多个指针只向它如下:

int main()

{

Ref *p1 = new Ref();

p1->showMsgRef();

Ref *p2 = p1;

p2->retain();

p2->showMsgRef();

..... // 这里应该还有释放资源得部分。

return 0;

}

看到了吧,这就是同一个对象的操作多个指针的引用,例子中没有对Ref new 两次,就实现p1,p2对其操作,只是在使用的时候,调用一次retain函数就行了。这样是为了表示

有某个指针在引用它,如果再有p3,p4呢,同理可得。

那么如何释放呢,我们继续往里面添加realse函数,为了模仿CCASSERT,所以在头文件还需定义另一个宏

void Ref::release()

{

--_reference;

CCASSERT(_reference >0,"这引用计数应该大于等于0");

if(_reference ==0)

{

delete this;

}

}

所以目前的所用代码如下所示:

#include<iostream>

using namespace std;

#include <assert.h>

#define CCLOG(strFormat, value) printf(strFormat, value) // 暂时用这个宏模仿cocos2dx3.2里面得日志打印

#define CCASSERT(n, msg) assert(n) // 看上面的注释

class Ref

{

public:

Ref():_reference(1) {}//这里给引用计数初始化1,这是仿照cocos2dx3.2引擎里面得初始

virtual ~Ref(){CCLOG("it has been destroyer%s","");}

void showMsgRef(){CCLOG("This is a Ref class, and its _reference:%dn",_reference);}

void retain(){&#;&#;_reference;}

void release();

private:

int _reference ; // 引用计数

};

void Ref::release()

{

CCASSERT(_reference >0,"这引用计数应该大于等于0");

--_reference;

if(_reference ==0)

{

delete this;

}

}

// 这里说说为什么CCASSERT(_reference > 0,"这引用计数应该大于0"),中的_reference > 0,其实道理很简单,因为刚开始初始化的时候,引用计数为1,是吧,如过小于1,那表明这个对象已经被删除,故断言:其必须为大于0, 不信去看下cocos2d 3.2里面的源码。

在使用的使用可以这样,在我不需要对这个对象引用了,就调用release一下,如下:

int main()

{

Ref *p1 = new Ref();

p1->showMsgRef();

Ref *p2 = p1;

p2->retain();

p2->showMsgRef();

p2->release();

p2 = nullptr;//释放候设为空,习惯而已

p1->release();

p1 = nullptr;

return 0;

}

结果如下:

看到结果了吧,后面那句表明这个对象已经被释放了。

好了,关于Ref,引用计数部分就先到这,不知理解否,呵呵,没事,多几遍,看不懂那是我的问题,因为我从来就不擅长写博客文章的,只是

现在练练而已。那么cocos2dx3.2,自动释放池又是咋回事呢,cocos2dx里面看到很多这句代码:

pRet->autorelease();

不着急,慢慢来。

接着我们构造自动释放池

class AutoreleasePool

{

public:

AutoreleasePool(const std::string &name);

void addObject(Ref *object);

void clear();

private:

std::vector<Ref*> _managedObjectArray;

const std::string _name;

};

AutoreleasePool::AutoreleasePool(conststd::string &name)

:_name(name)

{

PoolManager::getInstance()->push(this);

}

void AutoreleasePool::clear()

{

//。。。还有些代码

for (const auto &obj : _managedObjectArray)

{

obj->release();

}

_managedObjectArray.clear();

}

void AutoreleasePool::addObject(Ref *object)

{

_managedObjectArray.push_back(object);

}

好了,自动释放池已经建好了,接下来,我们还有建立一个自动释放池管理类,用来管理Autorelease;

class PoolManager

{

public:

static PoolManager* getInstance();

friend class AutoreleasePool;

void push(AutoreleasePool *pool);

void pop();

private:

PoolManager();

~PoolManager();

static PoolManager* s_singleInstance;

std::vector<AutoreleasePool*> _releasePoolStack;

};

PoolManager* PoolManager::s_singleInstance =nullptr;

PoolManager *PoolManager::getInstance()

{

if (s_singleInstance ==nullptr) {

s_singleInstance =newPoolManager();

newAutoreleasePool("cocos2d autorelease pool");

}

returns_singleInstance;

}

void PoolManager::push(AutoreleasePool *pool)

{

_releasePoolStack.push_back(pool);

}

void PoolManager::pop()

{

_releasePoolStack.pop_back();

}

PoolManager是个单例,这里说说为什么在声明中加入

friend class AutoreleasePool;

主要是因为在PoolManager里面使用了

new AutoreleasePool("cocos2d autorelease pool");看到了吧,呵呵。为什么要这样添加呢?嘿嘿

我们返回去看看自动释放池的构造函数:

AutoreleasePool::AutoreleasePool(conststd::string &name)

:_name(name)

{

PoolManager::getInstance()->push(this);

}

哎,这下明白了吧,不过这里这里会遇到像以下的小问题:

为什么会这样呢,因为我出于演示的目的,将Autorelease,PoolPoolManager的定义都写在一起了,还有我忘了在

Ref类里面添加

Ref* autorelease();

Ref* Ref::autorelease()

{

PoolManager::getInstance()->getCurrentPool()->addObject(this);

return this;

}

现在加上,请在看这里又使用了PoolManager,可能也会出现类&#;上面的小问题,好了,我再次调整,到目前为止所有到代码如下:

#include<iostream>

using namespace std;

#include <assert.h>

#include <vector>

#define CCLOG(strFormat, value) printf(strFormat, value) // 暂时用这个宏模仿cocos2dx3.2里面得日志打印

#define CCASSERT(n, msg) assert(n) // 看上面的注释

class Ref

{

public:

Ref():_reference(1) {}//这里给引用计数初始化1,这是仿照cocos2dx3.2引擎里面得初始

virtual ~Ref(){CCLOG("it has been destroyer%s","");}

void showMsgRef(){CCLOG("This is a Ref class, and its _reference:%dn", _reference);}

void retain(){&#;&#;_reference;}

Ref* autorelease();

void release();

private:

int _reference ; // 引用计数

};

class AutoreleasePool

{

public:

AutoreleasePool(const std::string &name);

void addObject(Ref *object);

void clear();

private:

std::vector<Ref*> _managedObjectArray;

const std::string _name;

};

class PoolManager

{

public:

static PoolManager* getInstance();

friend class AutoreleasePool;

AutoreleasePool* getCurrentPool() const;

void push(AutoreleasePool *pool);

void pop();

private:

PoolManager();

~PoolManager();

static PoolManager* s_singleInstance;

std::vector<AutoreleasePool*> _releasePoolStack;

自动释放池是吗,是否可以这样模仿,超简单,嘿嘿(自动释放池原理,本质)

};

Ref* Ref::autorelease()

{

PoolManager::getInstance()->getCurrentPool()->addObject(this);

return this;

}

void Ref::release()

{

CCASSERT(_reference >0,"这引用计数应该大于0");

--_reference;

if(_reference ==0)

{

delete this;

}

}

AutoreleasePool::AutoreleasePool(conststd::string &name)

:_name(name)

{

PoolManager::getInstance()->push(this);

}

void AutoreleasePool::clear()

{

//。。。还有些代码

for (const auto &obj : _managedObjectArray)

{

obj->release();

}

_managedObjectArray.clear();

}

void AutoreleasePool::addObject(Ref *object)

{

_managedObjectArray.push_back(object);

}

PoolManager* PoolManager::s_singleInstance =nullptr;

PoolManager *PoolManager::getInstance()

{

if (s_singleInstance ==nullptr) {

s_singleInstance =newPoolManager();

newAutoreleasePool("cocos2d autorelease pool");

}

returns_singleInstance;

}

PoolManager::PoolManager()

{

_releasePoolStack.reserve();

}

AutoreleasePool* PoolManager::getCurrentPool()const

{

return_releasePoolStack.back();

}

void PoolManager::push(AutoreleasePool *pool)

{

_releasePoolStack.push_back(pool);

}

void PoolManager::pop()

{

_releasePoolStack.pop_back();

}

到这里,基本用到的类都定义实现, 好了,先休息下, 累了吧,感觉我写了很多,不知道是否啰嗦,但为了阐述清楚,我尽量一步一步来实现。

。。。。。。十分钟过去了。。。。。

接下路,就是学会如何用啦,如何自己新建的类,然后,我将它放到自动释放池AutoreleasePool中,好吧,新建个精灵类,不过不够标准饿,滚他呢

,满足需求就ok。

class Sprite : publicRef

{

public:

static Sprite* create(conststd::string &fileName);

private:

bool initWithFileName(conststd::string fileName);

Sprite(){};

virtual ~Sprite(){CCLOG("the Sprite has been destroyed%sn","");}

};

Sprite* Sprite::create(conststd::string &fileName)

{

auto sprite = newSprite();

if (sprite && sprite->initWithFileName(fileName))

{

sprite->autorelease(); // 嘿嘿,这里就表示添加进自动释放池了

}

else

{

delete sprite;

sprite = nullptr;

}

return sprite;

}

bool Sprite::initWithFileName(conststd::string fileName)

{

return true;

}

正如注释所示,需要注意的地方,那好像还有一个没解决呢?那到底在cocos2dx3.2引擎里面什么时候创建第一个自动释放池呢?

还记得在自动释放池的构造函数里面的代码么,如下:

PoolManager* PoolManager::getInstance()

{

if (s_singleInstance ==nullptr)

{

s_singleInstance =newPoolManager();

// Add the first auto release pool

newAutoreleasePool("cocos2d autorelease pool"); // 别看了,就是这里我们在这里断电下,看看它在什么第一个创建自动释放池

}

returns_singleInstance;

}

好吧,我们看下图,一共三张图,有点多饿:

(一)

这是我在这里设置断点点地方,然后,我到堆栈里面返回去看,下面是第二张图:

接着,我们进入到GLView::create()函数里面去,在看,下面是第三张图:

嘿嘿,看到了吧,看到了吧,ret->autorealse();那autorelealse()里面到内容是什么呢?请看:

PoolManager::getInstance()->getCurrentPool()->addObject(this)

终于出来了在第一次调用 PoolManager::getInstance()的时候,它会执行PoolManager的构造函数,也就是执行这里:

PoolManager* PoolManager::getInstance()

{

if (s_singleInstance == nullptr)

{

s_singleInstance = new PoolManager();

// Add the first auto release pool

new AutoreleasePool("cocos2d autorelease pool"); }

return s_singleInstance;

}

当执行到 new AutoreleasePool("cocos2d autorelease pool"); 这里到时候,又调用了AutoreleasePool的构造函数,而我们再次看看AutoreleasePool的构造函数里面的情况:

AutoreleasePool::AutoreleasePool()

: _name("")

#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)

, _isClearing(false)

#endif

{

_managedObjectArray.reserve();

PoolManager::getInstance()->push(this);

}

,终于出来了,这时候就创建了第一个自动释放池,放到PoolManager的_managedObjectArray集合里面。看起来挺复杂的,不过看明白,懂得它的原理也不难,不懂?就多调试几下啊,呵呵。所以说在cocos2dx3.2里面在构建GLView界面多时候,就创建了第一个自动释放池,然后就凡是使用了 autorelease()的对象,都会把当前对象指针push 到当前的自动释放池当中,这第一自动释放池算是找出来了,那么它在什么时候检查里面的对象呢?答案是在绘制场景的时候,我们在AutoreleasePool的clear()函数里面断点:又有三张图,这时候就有人可能喷啦,又有三张图,草,哎,我才不管呢,不看也行,反正我也没打算给你看滴,嘿嘿:这上面是断点的地方。接着跟着堆栈返回去在DisplayLinkDirector里面:在看到了上一句了吗:drawScene(),是绘制场景啊。在往上看,在

int Application::run()里面执行下面图的内容:

我们知道它什么时候调用void AutoreleasePool::clear()啦,在它里面就遍历自动释放里面的对象,逐个调用release()

void AutoreleasePool::clear()

{

.. ...省略

for (const auto &obj : _managedObjectArray)

{

obj->release();

}

}

而在

Ref::release()里面,检查做操作,当引用计数为1的就释放掉。

void Ref::release()

{

CCASSERT(_referenceCount >0,"reference count should greater than 0");

--_referenceCount;

if (_referenceCount ==0)

{

....省略...

delete this;

}

}

是吧,没骗你吧。到这里,关于这些鸟东西前前后后,我都说了,有图有真相。

回归我的正题,既然是模仿吧,那就模仿个痛快来吧。上面已经创建了sprite, 接着我们还需创建DisplayLinkDirector 和 Director

class DisplayLinkDirector;

class Director : Ref

{

public:

static DisplayLinkDirector* getInstance();

Director(){};

virtual ~Director(){};

void drawScene();

public:

virtual void mainLoop() =0 ;

};

class DisplayLinkDirector : public Director

{

public:

DisplayLinkDirector(){};

virtual ~DisplayLinkDirector(){};

bool initWithFileName(const std::string fileName);

public:

virtual void mainLoop() override ;

};

void DisplayLinkDirector::mainLoop()

{

CCLOG("mainLoop in DisplayLinkDirector%sn","");

drawScene();

PoolManager::getInstance()->getCurrentPool()->clear();

}

void Director::drawScene()

{

CCLOG("the drawScene in Director invoken","");

}

static DisplayLinkDirector *s_SharedDirector =nullptr;

DisplayLinkDirector* Director::getInstance()

{

if (!s_SharedDirector)

{

s_SharedDirector = new (std::nothrow) DisplayLinkDirector();

}

return s_SharedDirector;

}

就是如何在xcode上用c&#;&#;创建定时器,让它就像cocos2dx3.2里面每隔1 / .0f执行一次绘制场景,检查自动释放池里面的对象呢? 这问题先留着吧,嘿嘿。我们简单使用它,说明原理即可

我们就简单使用它int main(){

auto sprite = Sprite::create("mm.png"); // 在这里添加 autorelease的时候,就表明创建了第一个自动释放池,并被PoolManager管理起来

Director::getInstance()->mainLoop(); // 这里表示检查自动释放池的对象。按理来说应该创建定时器,在下一帧调用的,由于没找到xcode c&#;&#;创建定时器,所有。。。

return 0;

}

输出结果如下:

长长的一大篇,万里长征终于结束了,也许有很多地方说得不对,请大神别喷,指出,批评改正就好,感觉写博文真累,就是那么个东西,非得写一堆

东西阐明,下次吧,有经验了,我尽量简明,我会逐步有所进步的,我相信自己,所有给自己一个yes!

最后给出关于以上demo的源码下载地址:

解决Android客户端运行Cococs2dx编写的游戏程序遇到的意外游戏中断导致的游戏黑屏问题 今天,在Android客户端运行的游戏,按HOME键,或者是意外终止游戏以后,再次返回游戏就会出现黑屏的问题,查找了好多资料,试验了好多办法,终于发

Cocos2dx -lua QuickXDev拓展 用cocos2d-x做开发的话,用的最多的开发语言就是c/lua了,而现在公司很多都比较看重开发速度,较多的公司都选择了lua作为开发语言,同时lua的热更新也

cocos2dx 不规则按钮的实现 最近研究了一下像素级的触摸处理,有时候我们用一个不规则的图形作为一个按钮,这个不规则的图形是一张矩形的png图片,很可能图片的实际有效的

标签: 自动释放池原理,本质

本文链接地址:https://www.jiuchutong.com/biancheng/372600.html 转载请保留说明!

上一篇:cocos2dx 3.2 屏幕适配的理解(cocos2dx屏幕适配解决方案)

下一篇:解决Android客户端运行Cococs2dx编写的游戏程序遇到的意外游戏中断导致的游戏黑屏问题(android遇到的难题,怎么解决的)

  • 预提所得税的计税依据
  • 住房公积金发票
  • 投资收益分红需要交企业所得税吗
  • 小规模纳税人收到专票后如何处理
  • 违反有关规定擅自开设银行账户的
  • 按利润总额的25%计算应交所得税
  • 金税三期个人所得税税率
  • 待抵扣进项税额是什么情况下用的
  • 小规模纳税人收入账务处理
  • 查询税务信用评级
  • 用友t3怎么删除损益结转凭证
  • 财务报表季度申报资产负债表怎么填
  • 固定资产减值准备属于什么科目
  • 购物预付卡怎么用
  • 资源管理器一直弹出
  • excel中如何选择只能选择的项
  • linux |bc
  • windows11启动卡在转圈圈
  • 银行承兑汇票的转让一般通过什么渠道
  • win10永久激活2021
  • group policy client服务未能登录解决方法
  • 一个更简单的无限级分类菜单代码
  • 销售旧设备如何开票
  • php的面向对象
  • 未开票收入开票
  • 公积金怎么做会计科目
  • 企业境外所得税额抵免限额应分国分项计算
  • 发行债券的会计分录摊销
  • 记录一次游戏
  • php项目怎么打包
  • 旅游业发票的税率是多少
  • 水利基金忘记申报怎么查
  • 外币应收账款汇兑损失计入
  • 低值易耗品需要计提吗
  • 专用发票能当月抵扣吗
  • 实施资本公积金的目的
  • 企业盈余公积的主要用途是
  • 个人写收据要写身份证号吗
  • 长期股权投资的账面价值怎么计算
  • 小规模纳税人防水工程专用发票税率是多少
  • 什么情况下需要做心脏造影
  • 税务局核定税种流程
  • 小微企业能申请高新吗
  • 安防工程注意事项有哪些
  • 结转制造费用用红字还是蓝字写
  • 增值税进项税转出有哪些
  • 公司购买的公司用车
  • 不良品怎么入账
  • 收到股权认购款怎么做账
  • 减免税款科目期末有余额吗
  • 成品油生产库存
  • 发票未到成本如何做分录
  • 哪些行业不适用作业法
  • 管理会计运用什么软件
  • 远程修改微信聊天记录
  • windows允许多用户登录
  • VMware虚拟机中安装MATE桌面环境
  • linux用
  • freebsd操作命令
  • win10网络身份验证失败
  • linux操作系统安装包
  • sunasServ.exe - sunasServ是什么进程 有何作用
  • netcfg -d
  • linux网卡bound
  • Win7系统如何打开磁盘管理工具
  • win8系统游戏
  • cocos2dx4.0教程
  • surf apk android
  • 批处理 全局变量
  • perl里怎么对数组实现一次遍历
  • python日历查询系统
  • python里!
  • python如何发送http请求
  • js使用类
  • javascript面向对象精要pdf
  • 掌上税务app
  • 企业出租房产的税收优惠政策
  • 车辆购置税多久能退回来
  • 2018年税务局
  • 新郑市税务局
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设