new, delete or release? release!

本文介绍了Cocos2dx中的内存管理机制,包括手动管理(使用new和release)及自动管理(autorelease)。详细解释了CCObject类的作用及引用计数原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文链接:http://blog.youkuaiyun.com/ring0hx/article/details/7946397

对于 CCObject* obj = new CCObject(),正确的释放方式:

应该是 obj->release() 而不是 delete obj;(具体可以参看 2dx 源码)

cocos2dx 的内存管理移植自 oc, 对于没有接触过 oc 的 C++ 开发人员来说是挺迷惑的。

不深入理解内存管理是无法写出好的 C++ 程序的,我用 oc 和 cocos2dx 也有一段时间了,

在此总结一下,希望对想用 cocos2dx 开发游戏的朋友有所帮助。


C++ 的动态内存管理一般建议遵循谁申请谁释放的原则,

即谁通过 new 操作符创建了对象,谁就负责通过delete来释放对象。

如果对象的生命周期在一个函数内,这很容易做到,在函数返回前 delete 就行了。

但一般我们在函数中 new 出来的对象的生命周期都会超出该函数体(例如作为函数的返回值),

否则我们可以直接在栈上创建对象,不需要使用动态内存,

也省去了内存管理的麻烦(当然大对象是不适合在栈上分配的)。

如果对象的生命周期超出了创建对象的函数,我们就很难再遵循谁申请谁释放的原则了,

我们必须在函数外的某个合适的地方释放对象,如果这个对象同时被多个对象引用,问题就很复杂了,

必须保证所有该对象的引用者都不再需要它了才可以释放,在实际使用中这点是很难保证的。

于是,各种内存管理技术应运而生了:垃圾回收器,智能指针,引用计数......

cocos2dx 移植于 oc,因此和 oc 一样使用了比较原始的引用计数的方法来管理内存。


cocos2dx 通过 CCObject 和 CCPoolManager 来实现内存管理。

所有使用 cocos2dx 引用计数机制的类都必须派生自 CCObject。

CCObject 有一个计数器成员变量 m_uReference,

当 CCObject 被构造时 m_uReference=1,表示该对象被引用1次。

CCObject 的 retain 方法可以使计数器加 1,release 方法可以使计数器减 1。

当计数器减到 0 时 release 方法会通过 delete this 来销毁自己。


手动内存管理

使用 retain 和 release,我们可以手动管理内存,通过 new 创建的对象,使用 release 来释放。

CCObject *obj=new CCObject();  
...   
obj->release();

和 new/delete 需配对使用一样,new/release 也要配对使用才可确保内存被释放。

有人会说这个把 delete 换成 release 有意义吗?需要注意的是这个的 release 并不等同于delete,

release只是表示引用计数减1,并不是真正销毁 obj 所占用的内存。

只有当 obj 的引用计数为 0 时内存才会被销毁。

下面的代码就展示了 release 和 delete 不同:

CCArray *array = CCArray::array();  
// m_uReference=1  
CCObject *obj = new CCObject();
// CCArray 的 addObject 方法会自动调用 obj 的 retain 方法,使引用计数加 1,表示拥有 obj,此时 m_uReference=2  
array->addObject(obj);
// 这里的 release 和 new 配对,obj 引用计数减 1,但是并不会释放 obj, 此时 m_uReference = 1;
obj->release();
// 在 release 之后我们依然可以正常使用 obj,它并没有被释放  
obj->doSomething();
// 当我们把 obj 从 CCArray 中移除时,CCArray 会自动调用 obj 的 release,此时 m_uReference = 0, obj 被销毁
array->removeObject(obj);
obj->doSomething(); // 错误,obj 已经被销毁

对于手动内存管理,我们需遵循 new/release,retain/release 配对使用的原则,

谁 new,谁 release;谁 retain,谁 release。

new 出来的对象如果是要加入到 cocos2dx 集合中,添加完后一定不要忘记 release,

集合类已经为你 retain 了对象,你还是要为你的 new 配对 release 一次,

否则当这个对象从集合中移除时不会被正确销毁。


自动内存管理

手动内存管理似乎比 new/delete 更麻烦,

而且并没有解决一开始我们提到的函数内创建的对象的生命周期超出函数怎么办的问题。

new 和 release 需配对使用,那在函数内创建的对象返回前我们需要调用一次 release,

在这之前如果我们没有把对象加入到什么集合中,对象就被销毁了,和使用new/delete是一样的。

自动内存管理就可以解决这个问题。

CCObject 有一个 autorelease 方法,

如果一个对象在用 new 关键字创建之后调用了 autorelease,我们就不必关心它的释放问题。

CCPoolManager 会在游戏的每一帧结束后自动释放这些 autorelease 的对象。

CCPoolManager 其实依然是通过引用计数来管理对象生命周期的,它里面有一个 CCAutoreleasePool,

我们调用 CCObject 的 autorelease 就是把自己加入到 CCAutoreleasePool 的对象数组里面。

当每一帧结束的时候,CCPoolManager 会将对象从数组中移除,

如果这时候对象的引用计数为 0,对象就自然被释放了。

对于用 new 关键字创建之后调用了 autorelease 的对象,不需要再 release 一次。


2dx 中的大部分类都可以通过静态工厂方法创建出这种会自动释放的对象,这是 2dx 的一条规则,

我们自己实现的类最好也遵循这样的规则,以免引起其他开发人员误会。

如果一个对象是通过类的静态方法创建而不是 new 出来的,我们就不需要 release 它。


其实这里的自动并没有我们想得那么好,对于像 C#,Java 这种托管语言,

虚拟机为你完成了所有内存管理工作,程序员完全从内存分配和释放中解脱了出来。

cocos2dx 的 autorelease 只不过每帧结束后自动在为我们释放了一次对象,

如果我们希望创建的对象在下一帧仍然可以使用,我们需要显式地 retain 

一下这个对象或者把对象加入到集合中(集合会帮我们 retain 一次)。

既然 retain 了,我们还是不能忘记在适当的地方 release。

比较常见的用法是创建一个 autorelease 对象作为类成员变量,

我们在通过静态方法得到实例的指针后除了赋值给类成员,

还要 retain 一次,然后在类的析构函数中 release 一次。

如果没有 retain,以后使用该成员的时候就会因为对象被销毁而发生内存访问错误,

这是新手很容易遇到的陷阱。

In C, memory allocation is typically done using the `malloc` function, which is part of the C standard library. Here's how it works: **C - malloc()** ```c void* malloc(size_t size); ``` `malloc` allocates a block of uninitialized memory of the specified size in bytes. If successful, it returns a pointer to the allocated memory; otherwise, it returns `NULL`. The programmer is responsible for managing this memory by calling `free()` when no longer needed. **C++ - new** In C++, memory allocation is performed using the `new` keyword, which is part of the language itself. It also involves dynamic memory allocation but provides additional safety features: **C++ - new** ```cpp void* operator new(size_t size); ``` `new` does similar work as `malloc`, allocating memory and returning a pointer. However, C++ adds constructors for objects (if applicable), meaning that if you allocate an object with `new`, its constructor will be called automatically upon allocation. Additionally, C++ provides `delete` to deallocate the memory when no longer needed: ```cpp void operator delete(void* ptr); ``` **Differences:** 1. **Error handling:** C++'s `new` includes bounds checking, while `malloc` may not. This means `new` can throw exceptions if memory cannot be allocated, whereas `malloc` silently fails. 2. **Resource management:** In C, you must manually call `free` to release memory. In C++, this is handled implicitly with `delete` or `delete[]` for arrays. 3. **Memory alignment:** C++ ensures proper alignment for certain types, while `malloc` does not guarantee alignment. 4. **Object construction/destruction:** C++'s `new` supports automatic construction and destruction of objects, which is not possible with `malloc`.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值