Object/Particle pool memory problem

Hey all,
I’m trying to make a good particle/object pool manager for myself, and it works good - until I restart the Scene and try to use it again… I’m a beginner at c++ so maybe it’s something easy I’m missing. Anyways, here are some more details…

Usage:

fxMgr = Fx::create();
fxMgr->retain();
greenStarPoolIdx = fxMgr->addPool(fxNode, Fx::FxType::GREEN_STAR, 2);

later

auto star = fxMgr->getGreenStar(greenStarPoolIdx);

(do something with the star)

I recently made it so that the Fx class inherits from Ref. I used to have it as a unique_ptr to avoind having to deal w/ memory management, when changed it to inherit Ref to let cocos handle it instead.
Since I called retain, I have this in my scene’s destructor (can’t use addChild on it since it doesn’t inherit Node):

fxMgr->release();

Inside the Fx class; (except for methods for getting particles and adding object pools):

virtual ~Fx();
Fx();
Vector<ParticlePool*> _pools; <- used have it as std::vector<ParticlePool*>
ParticlePool.h (also inherits from Ref now to use cocos's own reference counting)

int particleIdx;
Vector<Node*> _pool;
virtual ~ParticlePool();
ParticlePool();

public:
Node* nextItem();
void add(Node* item);
static ParticlePool* create();

particle pool destructor

ParticlePool::~ParticlePool()
{
	CCLOG("pool dtor");

	for (size_t i = 0; i < _pool.size(); i++)
	{
		_pool.at(i)->release();
	}
}

Now, to the problem
When going to another scene, using breakpts, I can see the destructors for the Fx- and ParticlePool class being called, but not my GreenStar class (which the pool is holding).

Edit: updated the constructor to call release on all the items, now the destructor is called for those classes too. But I thought cocos Vectors would do this automatically? I don’t need to delete _pool though, right?

I can use the fxManager once, then when I restart or exit and re-enter the scene and try to use it again, it’s "0x00000000 " when I’m about to use it (after a key press).
I just can’t understand. Even if it was a memory leak I was at least expecting it to work since I’m making a new object? I need help.

How to create fxNode? Did retain() it or not use autorelease? It won’t destruct if it was retained.

greenStarPoolIdx = fxMgr->addPool(fxNode, Fx::FxType::GREEN_STAR, 2);

fxNode is a SpriteBatchNode (for better performance if you need lots of stuff at once).
I make it like so:

fxNode = SpriteBatchNode::create("images/green_star.png");

and then

addChild(fxNode);

but I do not call retain() on it. Guess it’s autorelease then?

It looks fine. I don’t know where is the problem exactly. can you post complete code here?

I updated my post above with some new info. Is there something in particular you want to look at?

ParticlePool::~ParticlePool()
{
	CCLOG("pool dtor");

	for (size_t i = 0; i < _pool.size(); i++)
	{
		_pool.at(i)->release();
	}
}

Don’t release() Nodes in Vector unless you call retain() explicitly before adding to vector. Please look into cocos2d::Vector class, the vector will retain the Ref* once adding to vector and release it before it is removed or the vector destruct.

I don’t know what’s reason of your problem exactly yet, but maybe the usage is incorrect in some where.

Ah, right. I’ll keep that in mind.
Here’s the Pool class, notice anything wrong here?


ParticlePool::~ParticlePool()
{
	CCLOG("pool dtor");
}

ParticlePool::ParticlePool()
{
	particleIdx = 0;
}

ParticlePool* ParticlePool::create()
{
	auto obj = new (std::nothrow) ParticlePool();
	if (obj)
	{
		obj->autorelease();
	}
	else
	{
		delete obj;
		obj = nullptr;
	}
	return obj;
}

Node* ParticlePool::nextItem()
{
	auto p = _pool.at(particleIdx);

	// item is busy?
	if (p->isVisible())
	{
		return nullptr;
	}

	if (++particleIdx == _pool.size())
	{
		particleIdx = 0;
	}

	return p;
}

void ParticlePool::add(Node* item)
{
	_pool.pushBack(item);
}

Sorry, I can’t point out the problem yet.

Ok, just to rule this one out…

{
	Vector<GreenStar*> lst;

	for (size_t i = 0; i < 3; i++)
	{
		GreenStar* item = GreenStar::init();
		lst.pushBack(item);
	}
}

// <-- Should I expect the destructors for GreenStar class here?

I never see the destructors being called for the class I put into the pool vector. That can’t be right, can it?

I just realized that I never called autorelease() on the GreenStar class (among many others) and that was the reason I never saw the destructors.
It never crossed my mind to do this because I read that cocos2d used ref. counting, and in my mind ref. counting would mean that the object would be destroyed if ref count would reach 0 - unless to call retain() on it… so is retain being called somewhere else then?

I solved it. Still not sure how it works but the problem is gone at least.

I tried to move the problematic code to my onTouchBegan callback, and was surprised to see that the problem did not occur there; I could restart the state and it would still work, hmm.

Then I looked at how I set up my listeners. I had been using a keyboardlistener like so:

auto kbListener = EventListenerKeyboard::create();
kbListener->onKeyPressed = CC_CALLBACK_2(GameModeA::onKeyPress, this);
eventDispatcher->addEventListenerWithFixedPriority(kbListener, 1);

and touchListener like so:

auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(GameModeA::onTouchBegan, this);

What I needed to change in order for the kbListener to work was instead of using a fixed priority, do:

auto kbListener = EventListenerKeyboard::create();
kbListener->onKeyPressed = CC_CALLBACK_2(GameModeA::onKeyPress, this);
eventDispatcher->addEventListenerWithSceneGraphPriority(kbListener, this);

If anyone can explain why the fixed priority one caused problems for me, it’d be interesting to hear. But I’m glad it’s fixed. This was a sneaky one for sure.

@kevinwu1024 has good advice, also SpriteBatchNode isn’t really needed much anymore unless we don’t auto-batch how you need or you are using objects that are not auto-batched by default.

unless we don’t auto-batch how you need or you are using objects that are not auto-batched by default.

how does one know what is auto-batched and what is not?

Sprites, Labels, UI elements to name a few. Cocos2d-x v3.0 release notes I think have more information as well. It has been a while since I have read that version.

Ok, maybe I should read those too. Thanks!