没有Mac,在windows下用VS2010发现用Visual Leak Detector检测不出retain()和release()的泄漏,只对new和delete有反应。
有没有好的工具推荐下啊?谢谢分享…
没有Mac,在windows下用VS2010发现用Visual Leak Detector检测不出retain()和release()的泄漏,只对new和delete有反应。
有没有好的工具推荐下啊?谢谢分享…
哎~ 还是没搞懂…
这中间的过程我还没细研究哈,因为我知道他内部肯定会各种析构,所以我一般会用
spritewithfile或者spritewithframename来建立我的精灵
狠少new
— Begin quote from ____
juckerpp 发表于 2012-8-14 21:40 url
这中间的过程我还没细研究哈,因为我知道他内部肯定会各种析构,所以我一般会用
spritewithfile或者spritew …
— End quote
嗯嗯 我也只是觉得:
CCSprite *sprite = CCSprite::spriteWithFile(“Button1.png”);
sprite->retain();
没手动release一次的话,vld应该给我一个leak的提示。。。
— Begin quote from ____
skoky 发表于 2012-8-16 08:39 url
这个就是cocos2d-x 当中设计的巧妙之处了。
一般的自动管理思维应该是 有个管理池,里面放着所有要自动 …
— End quote
非常感谢…skoky果然是大神啊~ 顿时开朗了… 学到了很多…
就是说其实自动释放对象只存在一帧的时间内,帧结束以后没有被delete掉的就成了普通的对象…接着就交给场景管理。
呃呃呃…我这还有两个问题:
1、场景释放的时候,是把它管理的对象release一遍 还是 delete一遍? 应该是delete吧?这样即使有对象的引用计数大于1也能销毁对象。
2、上面说的交给场景管理的是指node对象吧?如果是一般的数据源对象,像CCMutableArray<CCSpriteFrame *>::arrayWithObjects(…)这样的是不是要自己手动管理:初始化后retain一次然后在场景的析构中release?
我问题有点多…不好意思…有没有好书推荐一两本?想拿来充充电,发现好多地方不懂…好难受…
非常感谢…
— Begin quote from ____
CoCo漫游 发表于 2012-8-16 16:32 url
非常感谢…skoky果然是大神啊~ 顿时开朗了… 学到了很多…
就是说其实自动释放对象只存在一帧的时 …
— End quote
我是实践主义者。一般弄不明白的就打开源码看,要么就跟踪断点进去看。这样肯定能理解这是怎么样处理的。
1、场景也是普通的ccnode,所以释放子节点也是release。
2、数据源对象当然需要自己来管理了,一般数据就放在一个类里面,这个类析构的时候释放掉资源就行了。
— Begin quote from ____
juckerpp 发表于 2012-8-14 21:59 url
CCSprite *sprite = CCSprite::spriteWithFile(“Button1.png”);
sprite->retain();
— End quote
刚搞了把DOTA…
我是这样想的:
CCSprite *sprite = CCSprite::spriteWithFile(“Button1.png”);//这里count=1;
sprite->retain();//retain一次以后 count=2;
后面我一直没手动调用release(),所以它的count一直是2。
当自动释放池clear的时候,自动release一次,那count–等于1,所以这个时候不会delete它,就没有释放掉。
那应该会报leak。。。
////////////////////////////////////////////////////////////////////////////////
// $Id: vld.h,v 1.1 2011/11/28 08:44:48 chengjing Exp $
//
// Visual Leak Detector (Version 1.0)
// Copyright (c) 2005 Dan Moulding
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// See COPYING.txt for the full terms of the GNU Lesser General Public License.
//
////////////////////////////////////////////////////////////////////////////////
#pragma once
#ifdef _DEBUG
////////////////////////////////////////////////////////////////////////////////
//
// Configuration Options
//
// Configuration flags
#define VLD_CONFIG_AGGREGATE_DUPLICATES 0x1
#define VLD_CONFIG_SELF_TEST 0x2
#define VLD_CONFIG_SHOW_USELESS_FRAMES 0x4
#define VLD_CONFIG_START_DISABLED 0x8
#ifndef VLDBUILD
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// If VLD_AGGREGATE_DUPLICATES is defined, then duplicated leaks (those that
// have the same size and call stack as a previously identified leak) are not
// shown in detail in the memory leak report. Instead, only a count of the
// number of matching duplicate leaks is shown along with the detailed
// information from the first such leak encountered.
#ifdef VLD_AGGREGATE_DUPLICATES
#define VLD_FLAG_AGGREGATE_DUPLICATES VLD_CONFIG_AGGREGATE_DUPLICATES
#else
#define VLD_FLAG_AGGREGATE_DUPLICATES 0x0
#endif // VLD_AGGREGATE_DUPLICATES
// If VLD_MAX_DATA_DUMP is defined, then the amount of data shown in user-data
// memory dumps will be limited to the specified number of bytes.
#ifdef VLD_MAX_DATA_DUMP
unsigned long _VLD_maxdatadump = VLD_MAX_DATA_DUMP;
#else
unsigned long _VLD_maxdatadump = 0xffffffff;
#endif // VLD_MAX_DATA_DUMP
// If VLD_MAX_TRACE_FRAMES is defined, then the number of frames traced for each
// allocated memory block when walking the stack will be limited to the
// specified number of frames.
#ifdef VLD_MAX_TRACE_FRAMES
unsigned long _VLD_maxtraceframes = VLD_MAX_TRACE_FRAMES;
#else
unsigned long _VLD_maxtraceframes = 0xffffffff;
#endif // VLD_MAX_TRACE_FRAMES
// If VLD_SELF_TEST is defined, then Visual Leak Detector will perform a memory
// leak self-test, by intentionally leaking memory, to ensure that it is able to
// correctly detect memory leaks internal to Visual Leak Detector.
#ifdef VLD_SELF_TEST
#define VLD_FLAG_SELF_TEST VLD_CONFIG_SELF_TEST
#else
#define VLD_FLAG_SELF_TEST 0x0
#endif // VLD_SELF_TEST
// If VLD_SHOW_USELESS_FRAMES is defined, then all frames traced will be
// displayed, even frames internal to the heap and Visual Leak Detector.
#ifdef VLD_SHOW_USELESS_FRAMES
#define VLD_FLAG_SHOW_USELESS_FRAMES VLD_CONFIG_SHOW_USELESS_FRAMES
#else
#define VLD_FLAG_SHOW_USELESS_FRAMES 0x0
#endif // VLD_SHOW_USELESS_FRAMES
// If VLD_START_DISABLED is defined, then Visual Leak Detector will initially
// be disabled for all threads.
#ifdef VLD_START_DISABLED
#define VLD_FLAG_START_DISABLED VLD_CONFIG_START_DISABLED
#else
#define VLD_FLAG_START_DISABLED 0x0
#endif // VLD_START_DISABLED
// Initialize the configuration flags based on defined preprocessor macros.
unsigned _VLD_configflags = VLD_FLAG_AGGREGATE_DUPLICATES | VLD_FLAG_SELF_TEST |
VLD_FLAG_SHOW_USELESS_FRAMES | VLD_FLAG_START_DISABLED;
#ifdef __cplusplus
}
#endif // __cplusplus
////////////////////////////////////////////////////////////////////////////////
//
// Linker Directives
//
// Link with the appropriate Visual Leak Detector library. One of: multithreaded
// DLL, multithreaded static, or single threaded. All three link with debug
// versions of the CRT.
#ifdef _DLL
#pragma comment (lib, "vldmtdll.lib")
#else
#ifdef _MT
#pragma comment (lib, "vldmt.lib")
#else
#pragma comment (lib, "vld.lib")
#endif // _MT
#endif // _DLL
// Force a symbolic reference to the global VisualLeakDetector class object from
// the library. This enusres that the object is linked with the program, even
// though nobody directly references it outside of the library.
#pragma comment(linker, "/include:?visualleakdetector@@3VVisualLeakDetector@@A")
#endif // VLDBUILD
#endif // _DEBUG
百度搜索vld 
— Begin quote from ____
CoCo漫游 发表于 2012-8-15 21:09 url
谢谢 热心的skoky大神… 认真看了几篇cocos2d-x的内存管理原理博文…
http://blog.csdn.net/a7833756 …
— End quote
这个就是cocos2d-x 当中设计的巧妙之处了。
一般的自动管理思维应该是 有个管理池,里面放着所有要自动释放的东西,如果引用计数为1 则表示只有管理池在引用就可以释放。这应该是一般设计。
那么cocos2d-x是怎么做的呢, 其实它也有内存管理池,只不过是每帧都会release里面所有的对象一次, 然后从池里面删除。这么做的好处是不用每帧都去循环一个池里所有的对象检测。
那么现在来理解创建CCObject对象:
初始创建对象 count = 1;
autorelease 加入到内存管理池里面,count还是 1 , 这里的做法是把初始的那个引用计数赋值给管理池。
如果这个时候我们没有把这个object加入场景,或者自己retain.在这一帧结束的时候,管理池的那次释放就会销毁这个对象。
如果已经加入了场景,那么在这一帧结束的时候,管理池的释放,只会减去一次count,因为加入了场景所以count至少是2.
这样管理池就不再管理这个对象了,那么它由场景管理。在场景释放的时候会把这个对象销毁。
cocos2d内存引用计数是这样的。
首先一个new出来的object对象初始的引用计数为1,在autorelease后 引用计数还是为1.
在这一帧结束的时候,autorelease会自己release一次,如果这个时候你的object对象没有使用就自动释放了 。
也就是说我们创建一个sprite的时候,如果没有加入场景里面那么着帧结束就没了。加入场景才能保证不被释放。
分析一下下面的引用计数:
CSprite *sprite = new CCSprite; //1
sprite->autorelease();//1
sprite->retain();//2
sprite->release();//1
在帧结束的时候会自动释放一次 。
— Begin quote from ____
juckerpp 发表于 2012-8-13 23:43 url
百度搜索vld
— End quote
我用的就是这个 vld 2.2.3
但是我这有个问题:
CCSprite *sprite = CCSprite::spriteWithFile(“Button1.png”);
sprite->retain();
后面没有调用sprite->release()不报leak:
No memory leaks detected.
Visual Leak Detector is now exiting.
但是如果这样写:
CCSprite *sprite = new CCSprite;
sprite->autorelease();
sprite->retain();
没有调用release的话就会报:
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 3 at 0x012867C8: 456 bytes ----------
Call Stack:
f:cocos2d-xzlsr_3_bearzlsr_3_bearclasseshelloworldscene.cpp (45): Zlsr_3_bear.win32.exe!HelloWorld::init + 0xA bytes
…
…
Visual Leak Detector detected 1 memory leak (492 bytes).
Largest number used: 900 bytes.
Total allocations: 900 bytes.
Visual Leak Detector is now exiting.
这是什么情况?
因为你new了一个新的对象,如果你用的是spritewithxxxx,就等于将内存交给了cocos2d-x去管理
如果你使用 sprite = new CCspirte的话,那么就等于内存交给你自己管理
你注意看CCsprite的头文件描述,我记得明确说明了他是一个autorelease 的obj,所以关于sprite的内存管理你可以完全交给cocos2d-x来运作
— Begin quote from ____
skoky 发表于 2012-8-16 17:23 url
我是实践主义者。一般弄不明白的就打开源码看,要么就跟踪断点进去看。这样肯定能理解这是怎么样处理的。 …
— End quote
嗯 好方法!!!
学到很多~~
handshake:lol:lol
真的非常感谢…
— Begin quote from ____
juckerpp 发表于 2012-8-14 22:03 url
我的理解是,首先你告诉pool,这是一个交给你自动管理的对象。
然后你又让pool将它的count+1
然后pool就 …
— End quote
我试过:
CSprite *sprite = new CCSprite;
sprite->autorelease();
sprite->retain();
sprite->release();
这样没问题,不会报…
— Begin quote from ____
juckerpp 发表于 2012-8-14 16:15 url
因为你new了一个新的对象,如果你用的是spritewithxxxx,就等于将内存交给了cocos2d-x去管理
如果你使用 spr …
— End quote
但是我看CCSprite源码里面spriteWithXXX也是通过先new一个对象出来,然后在给加个autorelease再返回的:
CCSprite* CCSprite::spriteWithFile(const char *pszFileName)
{
CCSprite *pobSprite = new CCSprite();
if (pobSprite && pobSprite->initWithFile(pszFileName))
{
pobSprite->autorelease();
return pobSprite;
}
CC_SAFE_DELETE(pobSprite);
return NULL;
}
跟自己去:
CCSprite *sprite = new CCSprite;
sprite->autorelease();
中间有什么差别吗? 新手初学…求指导…非常谢谢
CCSprite *sprite = CCSprite::spriteWithFile(“Button1.png”);
sprite->retain();
retain代表你要使用一段之后,再交给cocos2d-x的内存池去释放这个对象,也就是说,你retain了一下,cocos2d-x后台就会+1,这个+1代表你的使用次数
也就是说你下文如果
sprite->xxxxx();
那么这个count就会-1
然后cocos2d-x的内存管理机制检测到count为0的时候,就会认定他为autorelease的对象,pool就会将它release掉,所以你在vld里估计是不会有leak的
— Begin quote from ____
是如果这样写:
CCSprite *sprite = new CCSprite;
sprite->autorelease();
sprite->retain();
没有调用release的话就会报:
WARNING: Visual Leak Detector detected memory leaks!
---------- Block 3 at 0x012867C8: 456 bytes ----------
Call Stack:
f:cocos2d-xzlsr_3_bearzlsr_3_bearclasseshelloworldscene.cpp (45): Zlsr_3_bear.win32.exe!HelloWorld::init + 0xA bytes
…
…
Visual Leak Detector detected 1 memory leak (492 bytes).
Largest number used: 900 bytes.
Total allocations: 900 bytes.
Visual Leak Detector is now exiting.
— End quote
我的理解是,首先你告诉pool,这是一个交给你自动管理的对象。
然后你又让pool将它的count+1
然后pool就认为你还要用。。
然后报leak了。。
你可以做一个测试
1.就是retain之后在用一次
2.retain之后不用
看看分别是否报leak。。
总之他的内存pool的原理就是给每个对象加一个count来管理
— Begin quote from ____
skoky 发表于 2012-8-15 08:38 url
cocos2d内存引用计数是这样的。
首先一个new出来的object对象初始的引用计数为1,在autorelease后 引用计 …
— End quote
谢谢 热心的skoky大神… 认真看了几篇cocos2d-x的内存管理原理博文…
http://blog.csdn.net/a7833756/article/details/7628328
http://blog.csdn.net/a7833756/article/details/7632199
我是不是可以这样理解:
每一帧都有一个CCAutoreleasePool对象去管理当前的autorelease对象,当帧结束的时候,CCAutoreleasePool对象就把它管理的autorelease对象release一遍。此时如果autorelase对象的引用计数变为0则delete对象,如果引用计数不为0,则说明对象还在使用或者发生了leak?
如果上面的理解可以的话, 我这还有个问题,毕竟一帧的时间是很短的,如果新建一个autorelease的sprite,添加到场景中,是怎样保证这个sprite能在多帧上一直存在而不被自动释放掉?是不是在自动释放上一帧的资源前,先重画好了下一帧,在这个初始过程中,又对sprite的引用计数加了1,才能保证sprite的引用计数的平衡,直到我们退出场景? 这样感觉消耗就有点大吧…
真心求解答…我做了一年IOS应用的,内存管理这块一直没深入…一直也没接触过游戏引擎和图形重画的机制…想转游戏方向才学的C++和Cocos2d-x…如果有什么地方不对的,求指出…求带领…不胜感谢…
说了一大堆,一开始的问题并没有得到解答啊??
autorelease()调用一次就会在autoreleasepool里记录一次,然后在mainloop结束的时候把autoreleasepool里记录的object都调用一次release,然后清空autoreleasepool!!!
也就是说,如果在autoreleasepool::clear()里调用obj->release()的时候,如果obj的_referencecount大于1,那么这个obj就不会被delete!!!
并且,在没有后续调用obj->autorelease()的情况下,autoreleasepool里不会再记录这个obj!!!
程序退出时会调用Director::purgeDirector(),这个函数会显式调用当前scene的release一次,然后调用所有记录在案的Node的release()一次(Vector::clear)!!!
只有_referencecount为0时才会delete obj!!!
结论,如果你没有调用obj的release或者autorelease,以使obj的_referencecount <=1,那么这个obj就不会被delete从而形成内存泄漏!!!
至于VS为什么没检测到这些内存泄漏,抱歉,才看这个引擎2天的我也是一头雾水!
用VC自带的_CrtSetDbgFlag()函数试了一下,发现即使是HelloWorld都有一大堆内存泄漏。。。何解?!!!!