在vs下,大家用什么来检测内存泄漏啊?

没有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 :slight_smile:

— 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: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都有一大堆内存泄漏。。。何解?!!!!