I’m desperately trying to track down a crash that is occurring in the wild, but I cannot reproduce. I don’t think it’s memory related (ie: running out of) but I think it’s a sequence issue. The users who report it report the same game process.
So I wonder if I’m doing something wrong with actions and the render loop…
Here is an example…
As a character moves forward the scene is rendered x number of steps. This action would have been triggered as a result of a UI interaction eg: touching a ‘move forward gadget’
For each step and LandscapeView will be generated and the previous one destroyed.
auto actionfloat = ActionFloat::create(TRANSITION_DURATION, 0, target, [=](float value) {
options.here.x = options.moveFrom.x*(LANDSCAPE_DIR_STEPS - value) + options.moveTo.x*value;
options.here.y = options.moveFrom.y*(LANDSCAPE_DIR_STEPS - value) + options.moveTo.y*value;
if ( value >= target ) {
stopMoving();
return;
}
f32 result = value / target ;
options.movementAmount = result;
options.generator->Build(&options);
UpdateLandscape();
});
this->runAction(EaseSineInOut::create(actionfloat));
Now I can’t see any reason why current_view which is the only LandscapeView object would get released by the AutoReleasePool. Which I presume is the one in the main loop after DrawScene, because the only time LandscapeView could be released is when it’s removed from the children of these Scene at the top of UpdateLandscape.
So that suggests I’m missing something with how Actions are running and how the MainLoop is running. If they were two different threads I would absolutely get it… but I don’t think that’s the case…
void panel_look::UpdateLandscape()
{
static auto creatingView = false;
if (creatingView) {
return;
}
creatingView = true;
if ( current_view ) {
removeChild(current_view);
current_view->release();
current_view = nullptr;
}
auto* newView = LandscapeView::create(&options);
newView->setAnchorPoint(Vec2::ZERO);
newView->setPosition(Vec2::ZERO);
newView->setLocalZOrder(ZORDER_FAR);
addChild(newView);
newView->retain(); // If you're keeping a reference to a cocos2d::Ref object, then you should always explicitly retain it
current_view = newView;
creatingView = false;
}
I’m not certain if this is the cause of your issue, but you’re keeping a reference to a cocos2d::Ref object in current_view, and it’s just good practice to explicitly retain that object in this case, then release it when you’re no longer using it. If you don’t do this, you may end up with a dangling reference in current_view if the object it is pointing to has been removed from the parent and auto-released elsewhere.
Ok. Thanks for that. I don’t think that is my issue - but I will check through my code and make sure I always retain. I’ve been working on the principal that the reference is just a quick reference while it’s part of the scenes children, rather than me looking it up again from the child list.
The re-entrant thing is interesting, but not sure I can test as I can’t replicate the issue.
I now understand how I get releases in the auto release pool. It’s affectively because I’ve made two calls to update landscape during the same event. It’s a buy product of not having an isDirty type check in updatelandscape ie: Nothing has really changed but two triggers to UpdateLandscape have happened because of two different conditions during the same processing loop. None of them are re-entrant though.
Yeah that’s exactly how I handle it in my code too, especially for parts that would require too many look-ups of the specific object, so it’s much quicker to hold a reference to it, as long as you ensure the reference is always valid (via the retain/release).
Have you considered adding some kind of logging to your application? It would enable you to better track down issues on end-user devices, assuming you add the required checks and log them. You can have a button in the app that the user can click to upload the logs, or you can just use some kind of service that you send the logs to while your app is running (best to batch them, not send one by one).
Yes, I’m thinking of the logging, but it needs to be cocos too… this crash is when an object is released, and the two calls that are of interest are tiny_free_list_remove_ptr and free_list_checksum_botch, so it looks like something is being released twice or something… So I think It’s going to take a lot of logging.
BTW: Is it possible to attach the cocos console running on a Mac/Windows to the app running on an iPhone? I do have a friendly tester who can reproduce the issue with my TestFlight builds…