如何检测或者解决循环引用计数的问题(简单而行之有效的方法)?


A引用B,B引用A,导致对方引用计数增加,内存释放可能出现问题,大体这样。

下面是一个例子:

   
  //以下出现的类继承自Object
  
//Object中提供retain(引用计数增1)和release(引用计数减1)操作,
//autoRelease操作将该对象的存储释放工作交给辅助对象处理
class FPC_DLL DisplayObject:public EventDispatcher
{
public:

void setParent(DisplayObjectContainer* parent)
{
pParent_ = parent;
pParent_.retain(); //循环引用,引用计数出现问题
}
}

class FPC_DLL DisplayObjectContainer:public DisplayObject
{
private:

Array* pChildren_;

public:
~DisplayObjectContainer()
{
pChildren_.release();
}

void addChildAt(DisplayObject* child,uint32 index)
{
child->retain();
child->setParent(this);
//内含对child的retain操作
pChildren_->insertObject(child,FPC_MIN(pChildren_->count(),index));
child->release();
}
}

////////////////////////////////////////////////////////////////
{
DisplayObject* do = new DisplayObject;
DisplayObjectContainer* doc = new DisplayObjectContainer;
do.autoRelease();
doc.autoRelease();
doc.addChild(do);
//辅助对象释放存储可能出现问题
}

这里的问题还是比较直观的,还好解决,如果涉及的对象多一些,可能不是那么好发现了。

C++ objective-c

夏娜.f.轻音 12 years, 3 months ago

1,对象的retain和release要对应啊,DisplayObject类在void setParent(DisplayObjectContainer* parent)函数中retain了的对象并没有对应的release操作,你应该在 析构函数里面release一次;
2,你的计数关系是:新建的do(retainCount = 1);新建doc(retainCount = 1);都加入了autoReleasePool当中;进行doc.addChild(do)之后,do被首先被rerain了一次,紧接着自己(doc)被加到do中,被retain了一次,现在都retainCount都为2,然后do被加入到数组中,do 的retaincount 变为3,然后释放一次,变为2;现在:总体上是都为2;数组的retaincount为1
3,你现在的包含关系是,doc里面包含一个数组,数组包含着do,而do包含着doc,
4,你在释放do 的时候,是不会释放其成员变量pParent_(其实就是doc)的,因为没有地方release,doc释放不了,doc里面的数组也是不会释放,数组包含着do也就不会,这样死循环就造成了,你把析构函数加上去就不会有问题,但是 autoReleasePool释放是由事件延迟的!

珍妮贾啪嗒 answered 12 years, 3 months ago

Your Answer