retain earning和release倒底怎么玩

C++基础入门教程(五):new和delete
投稿:junjie
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了C++基础入门教程(五):new和delete,本文讲解了动态分配内存、new和delete的配对、new、delete与reatin、release的关系、动态数组等内容,需要的朋友可以参考下
对于以前没有接触过C++,然后初次接触Cocos2d-x的朋友来说,可能对于内存管理方面会比较生疏。
也经常会因为内存问题导致各种小Bug,我也曾经写过一篇retain和release倒底怎么玩?,用来驾驭Cocos2d-x的对象引用和释放也算是足够了。
但,难道大家就不想知道retain和release背后的秘密吗?(小若:不想。)
没错,今天木头来带大家走进科学,走进世界,一起来探讨C++的new和delete。(小若:没兴趣。)
好,既然大家都等不及了,那就开始吧~
1.动态分配内存
我们都知道,像“int num = 10;”这样的语句,声明了一个num变量,这个变量是需要内存来放置(就像你的文档需要硬盘来放置)。
对于这样的普通变量,是在编译的时候就分配好内存的。
没错,就像你出生的时候就决定了是男是女了。(小若:这个比喻感觉一点关系都扯不上啊!而且,谁说出生就决定的?!)
通过声明指针变量可以指向这些预先被分配好的内存地址,但,我们的指针可不仅仅是为此而存在的。
指针还可以保存动态分配的内存的地址。
那么,怎么动态分配内存呢?没错,就是new,如下代码:
// 可以这样
// 还可以这样
int *p = new int();
// 最后,要释放内存
通过new后面跟着类型,就可以创建用于保存某种类型的内存空间,然后返回这个内存空间的地址。
它和直接声明int变量的区别是:
1.new出来的变量在运行程序的时候才会申请内存,普通int变量在编译的时候就分配了内存;
2.new出来的变量在不使用的时候需要释放掉,否则会内存泄露,使用delete即可释放指针指向的内存空间。
2.new和delete的配对
动态申请的内存,在不使用的时候,一定不要忘了释放掉,否则会造成内存泄露。
粗俗地说,不,通俗地说,动态申请了内存,其实只不过是告诉操作系统,这块内存归我了,其他人不能使用。
操作系统会乖乖地把你申请的那块内存给你用,如果你没有明确告诉它你不需要这块内存,则这内存永远都只能由你来使用。(当然,会有意外情况的,这个忽略)
所以,绝对不要忘记,在不使用的时候,要delete掉。
只要你new了一个变量,那就必须有对应的delete。
3.new、delete与reatin、release的关系
现在来看看Cocos2d-x内存管理,它就是为了让我们可以忽略new和delete的配对而诞生的。
谁没事想天天记着自己在哪里new了,又在哪里忘了delete呢?
所以,retain和release诞生了。
Cocos2d-x的大部分对象都是使用create函数创建的,而create函数里主要做了2件事情:
1.调用new创建新对象,也就是申请了内存
2.将对象添加到内存管理池(具体引用计数规则我就不说了)
而Cocos2d-x的内存管理主要做的一件事情是:
1.检查所以参与内存管理的对象,对那些需要释放的对象调用delete,释放内存
因此,我们不需要自己去维护new和delete,创建对象的时候,把对象交给内存管理就可以了。
如果我们不调用retain,那么,对象会在下一次内存管理检查的时候被释放(也就是下一帧)。
同时,addChild等函数都会主动调用一次对象的retain函数,所以被addChild的对象都不会被释放。
而在离开场景等操作时,对象也会被调用release函数,抵消一次retain的作用。
除非必要,否则,我们不需要主动调用retain函数,这就是“自动内存管理”的基本规则了。
4.动态数组
除了动态创建变量之外,数组也可以动态创建:int *nums = new int[10];
而对应的,释放动态数组有点特别:delete []
在delete后面需要加上一个[],代表释放的是数组。
动态数组的使用和一般数组差不多,当然,也有小差别:
&int *nums = new int[3];
&&& nums[0] = 1;
&&& nums[1] = 2;
&&& nums[3] = 3;
&&& cout && nums[0];
&&& nums += 1;
&&& cout && nums[0];
第一次使用cout输出nums[0]时,输出的就是第一个元素的值:1。
但是,当调用了nums += 1时,指针nums已经指向了下一个地址,也就是nums[1]所在的地址。
所以,这时候再调用nums[0],输出的也是第一个元素的值,但此时的第一个元素已经不是1,而是2了。
好了,关于new和delete暂时到这里。
但关于指针的初步介绍还有一小部分,下一篇再介绍吧~
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具中国领先的IT技术网站
51CTO旗下网站
1.2.3 alloc/retain/release/dealloc 实现(2)
《Objective-C 高级编程: iOS与OS X多线程和内存管理》第1章自动引用计数,本章主要介绍从OS X Lion 和iOS 5 引入的内存管理新功能--自动引用计数。让我们在复习Objective-C的内存管理的同时,来详细了解这项新功能会带来怎样的变化。本节为大家介绍alloc/retain/release/dealloc 实现。
作者:黎华 译来源:人民邮电出版社| 09:36
1.2.3 alloc/retain/release/dealloc 实现(2)
对象的引用计数可通过retainCount 实例方法取得。
id&obj&=&[[NSObject&alloc]&init]; &NSLog(@&retainCount=%d&,&[obj&retainCount]); &/* &*&显示retainCount=1&*/&
执行alloc 后对象的retainCount 是&1&。下面通过GNUstep 的源代码来确认。
GNUstep/modules/core/base/Source/NSObject.m&retainCount &-&(NSUInteger)&retainCount &{ &return&NSExtraRefCount(self)&+&1; &} &inline&NSUInteger &NSExtraRefCount(id&anObject) &{ &return&((struct&obj_layout&*)anObject)[-1]. &}&
由对象寻址找到对象内存头部,从而访问其中的retained 变量。如图1-9 所示。
因为分配时全部置0,所以retained 为0。由NSExtraRefCount(self) + 1 得出,retainCount 为1。
可以推测出,retain 方法使retained 变量加1,而release 方法使retained 变量减1。
[obj&retain];&
下面来看一下像上面那样调用出的retain 实例方法。
GNUstep/modules/core/base/Source/NSObject.m&retain &-&(id)&retain &{ &NSIncrementExtraRefCount(self); &return& &} &inline&void &NSIncrementExtraRefCount&(id&anObject) &{ &if&(((struct&obj_layout&*)anObject)[-1].retained&==&UINT_MAX&-&1) &[NSException&raise:&NSInternalInconsistencyException &format:&@&NSIncrementExtraRefCount()&asked&to&increment&too&far&); &((struct&obj_layout&*)anObject)[-1].retained++; &}&
虽然写入了当retained 变量超出最大值时发生异常的代码,但实际上只运行了使retained 变量加1 的retained++ 代码。同样地,release 实例方法进行retained-- 并在该引用计数变量为0 时做出处理。下面通过源代码来确认。
[obj&release];&
以下为此release 实例方法的实现。
GNUstep/modules/core/base/Source/NSObject.m&release &-&(void)&release &{ &if&(NSDecrementExtraRefCountWasZero(self)) &[self&dealloc]; &} &BOOL &NSDecrementExtraRefCountWasZero&(id&anObject) &{ &if&(((struct&obj_layout&*)anObject)[-1].retained&==&0)&{ &return&YES; &}&else&{ &((struct&obj_layout&*)anObject)[-1].retained--; &return&NO; &} &}&
同预想的一样,当retained 变量大于0 时减1,等于0 时调用dealloc 实例方法,废弃对象。
以下是废弃对象时所调用的dealloc 实例方法的实现。
GNUstep/modules/core/base/Source/NSObject.m&dealloc &-&(void)&dealloc &{ &NSDeallocateObject&(self); &} &inline&void &NSDeallocateObject&(id&anObject) &{ &struct&obj_layout&*o&=&&((struct&obj_layout&*)anObject)[-1]; &free(o); &}&
上述代码仅废弃由alloc 分配的内存块。
以上就是alloc/retain/release/dealloc 在GNUstep 中的实现。具体总结如下:
在 Objective-C的对象中存有引用计数这一整数值。
调用 alloc或是 retain方法后,引用计数值加 1。
调用 release后,引用计数值减 1。
引用计数值为 0 时,调用 dealloc方法废弃对象。【责任编辑: TEL:(010)】&&&&&&
大家都在看猜你喜欢
热点热点头条头条热点
24H热文一周话题本月最赞
讲师:96427人学习过
讲师:27169人学习过
讲师:251754人学习过
精选博文论坛热帖下载排行
程序设计实践并不只是写代码。程序员必须评论各种折衷方案,在许多可能性之中做出选择、排除错误、做测试和改进程序性能,还要维护自己或其...
订阅51CTO邮刊http://blog.csdn.net/musicvs/article/details/8689345
retain和倒底怎么玩?
呼呼,好久没有发布教程了(小若:难得清静了,你为毛又出来吓人=&=),其实最近木头我在准备出版书籍的事情。但是貌似不太顺利,果然我还是积累不够,写书的过程压力好大,感觉写不出有趣的文字出来(小若:嗷、、、)。果然还是在博客写自由一些?嘿嘿~
最近以及最不是很近(小若:书里一定不能出现这些错误的语句,所以你才写不出来吧),不少朋友对的认识似乎有点模糊,今天我就和大家分享一下关于的知识吧
笨木头花心贡献,啥?花心?不呢,是用心~
转载请注明,原文地址:&
1.&为什么会有?
C++和不一样,有一套很方便的垃圾回收机制,当我们不需要使用某个对象时,给它赋予值即可。而了一个对象之后,不使用的时候通常需要掉。
于是,就发明了一套内存管理机制(小若:发你妹纸。。。),其实红孩儿的博客很详细地解释了的内存管理机制,我没有能力也不想重复解释。(小若:那你还写?)
Retain的意思是保持引用,也就是说,如果想保持某个对象的引用,避免它被释放,那就要调用对象的函数。(小若:为什么不就会被释放?)
2.&真正的凶手
既然旁白诚心诚意地问我,那我就光明正大地回答吧(小若:我今天没力气吐槽,好吧)。
一旦调用对象的函数,那么这个对象就被的内存管理机制给盯上了,如果这个对象没人认领,那就等着被释放吧。(小若:太久没吐槽,一时不知道吐什么好)。
3.&看代码实际点
说了这么多,还是上代码吧。
创建一个的项目,就直接拿开刀,修改函数,在最后添加一句代码:
(小若:是什么东东?)
testSprite是一个成员变量,在头文件里加上就可以了:
然后,最关键的来了,我们修改函数:
现在,运行项目,点击按钮,看看是什么情况?
(小若:报错了!)
如果大家知道怎么调试项目的话,我们在函数里断点,用调试模式运行项目,看看对象:
(小若:很正常啊,有什么特别的?)
正你妹纸啊,正!你才正!(小若:不要这么光明正大地赞我!)
我们应该能看到不少非正常数据,图中已经用红色圈圈标出来了,这代表对象被释放了,现在指向未知的位置。
这是很危险的,有时候它不会立即报错,但是在某个时刻突然崩溃!
要想解决这个问题,很简单,再次修改函数:
再次运行项目,看看还会不会报错?(小若:不会了,为什么?)
再次用调试模式运行项目,看看对象:
(小若:不正常!都是!!)
零你妹纸(小若:为什么今天你总是抢我的对白!)
这次我们看到的数据明显正常了。
4.&原理来了
好了,唠叨了一大堆,还没有进入正题。
首先,要想让对象参与内存管理机制,必须继承类(、等都继承了类)。
然后,调用对象的函数,对象就会被的内存管理机制盯上,在游戏的每一帧,内存管理机制都会扫描一遍被盯上的对象,一旦发现对象无人认领,就会将对象杀死!(小若:嗷残忍!)
如果不想让对象被杀死,那么就要调用对象的函数,这样对象就被认领了,一旦对象被认领,就永远不会被内存管理机制杀掉,是永远,一辈子。(小若:好朋友,一辈子)
但,对象一辈子都不被释放的话,那么就会产生内存泄露,你试试加载一个占内存的对象一辈子不释放,不折腾死才怪(小若:你去加载一个的对象本身就是闲的那个什么疼啊!)因此,当你不需要再使用这个对象时,就要调用对象的函数,这是和对应的。一般可以在析构函数里调用函数。
5.&实际情况
讲道理,大家都懂,但是,相信很多朋友在实际写代码的时候,还是会感觉很混乱。
比如,什么时候该?大家是不是发现,有时候不也不会报错?
其实这很简单,因为我们经常会在一个对象之后,添加到层里,如:
testSprite&=&CCSprite::create(&HelloWorld.png&);
this-&addChild(testSprite);
addChild函数就是导致大家混乱的凶手了,函数会调用对象的函数,为什么它要调用对象的函数呢?因为你都把对象送给它当孩子了,它当然要认领这个对象了!(小若:我懂了,嗷!)
于是,当我们把对象到时(不一定是,、都行),我们就不需要调用对象的函数了。
6.&那倒底什么时候要?
说了这么多,还是没有说清楚,什么时候要调用对象的。
很简单,当你把一个对象作为成员变量时,并且没有把对象到另外一个对象时,就需要调用函数。
7.&最后的最后
一定要记住,必须要调用了对象的函数之后,和函数才会生效,否则,一切都是徒劳。
因此,十分建议使用的方式创建对象,如:
这些就是retain表面上的知识了,至于retain源码级别的解说,请到红孩儿的博客吧,强烈推荐~
好了,不唠叨了困喇,睡大觉去
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:238224次
积分:5239
积分:5239
排名:第5499名
原创:227篇
转载:382篇
评论:96条
阅读:2943
阅读:3953
阅读:1759
文章:38篇
阅读:14391
(2)(2)(2)(2)(10)(1)(1)(4)(1)(4)(25)(80)(71)(18)(9)(20)(107)(7)(9)(28)(11)(12)(8)(13)(58)(34)(40)(10)(22)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'

我要回帖

更多关于 mqtt retain 的文章

 

随机推荐