-
-
Notifications
You must be signed in to change notification settings - Fork 214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Object::retain crash in Sprite::setSpriteFrame(std::string_view) #2292
Comments
Can you please show an example of the code? Specifically, which version of Also, if you take a look at
It explicitly states: The problem is the call to
If there are references to any of the frames from a texture atlas, then |
From my understanding, whenever setSpriteFrame(SpriteFrame* spriteFrame) is called, it will retain the spriteFrame and the director's purgeCachedData won't remove it as it is not unused. Even if, it is removed, the next time I call setAssets() method, addSpriteFramesWithFile should add it back and spriteNode->setSpriteFrame("image1.png"); should be safe to call. |
Yeah, that's true. But isn't it necessary to be called for _textureCache->removeUnusedTextures(); to even work. Since, sprite frames retain textures. |
That would be the obvious way it should work, but it's clearly not, and now I'm actually curious why this is so. The comment in the code, |
@aryamansingh2008 I cannot reproduce this issue at all. The only way I could get it to fail is if an invalid frame name is passed to The test code used is as follows:
The scheduled callbacks with 1 second delay between each are just there so I could see what is happening, but other than that they are not important. Does your code do anything else between the call to |
Same here, I am also unable to repro this. This is what I am doing using mGLSurfaceView.queueEvent whenever I receive low memory signal.
And the addSpriteFramesWithFile and setSpriteFrame part gets triggered from touch events like button click. I tried to reproduce it by doing this in director drawScene
|
|
The remark "but it's clearly not" means that the way it should work is not how it seems to be working, since it is resulting in a crash, with regards to the
My interpretation of the comment is based on the "do not", yet you are interpreting it to mean "is not". Perhaps you are right, and the comment should have been "is not removed by SpriteFrameCache::removeUnusedSpriteFrames". |
In another post you mentioned that you have modified the engine in some way. Are you able to compile your application with an unmodified version of Axmol and release that? Also, is there a specific reason to modify the engine rather than add that functionality in the project? Modifying the engine means you need to be 100% certain that those modifications are not the cause of the issues, and just to clarify, I'm not stating that they are. When posting an issue here, we cannot really help unless we are testing with the exact same engine code. An example of this was the ANR issue you posted, where the code was different to what is in Axmol (the |
My team has been using cocos 3.14 version for a long time and had added many custom functionalities on top of that like using graphemeCluster to calculate visible string length in Input Text Field, caching writeable path in android to avoid JNI calls, adding custom writeable path in macOS so that it doesn't use Documents folder, handle scale of RichImageElement in Rich Text, caching csb files in memory to avoid disk reads, UserDefault disk writes changed to per frame instead of per instruction for USER_DEFAULT_PLAIN_MODE, adding isSpriteFramesWithFileLoaded in SpriteFrameCache's addSpriteFramesWithFile implementation to again avoid disk reads, and so on. These custom changes were mostly around improving performance of the engine and might not necessarily apply for all. Said that, we have planned to move these custom changes out of the engine which we can and to raise PRs for the others to get those functionalities added in the axmol project. |
That would be good. Any luck tracking down the source of the crash? |
No, but the code causing us problem is this
I have added logs to narrow down the root cause of this. My assumption is that either there is a bug in the SpriteSheet full state or there is a bug in addSpriteFramesWithDictionary flow which is ignoring few sprite frames. Will update here once the logs are released in production. (I am unable to repro the issue) |
Any chance you could change the code to this equivalent code, so you will prevent the crash and log the issue:
At least then you would know that Also, is there any chance that |
We are scheduling this call back using AxmolEngine.runOnGLThread(runnable) and using runOnAxmolThread as well. I know it is redundant, but that surely isn't the problem here.
The logs I have added are doing similar work. I am logging result of |
@aryamansingh2008 I was responding to the post you put up, but you deleted it, so I'm not sure what is going on there. Regardless of that, you mentioned this:
That is correct. Sprite sheets must contain globally unique IDs for the frame entries in them, since they're all stored in the same list. This is mentioned in the wiki post here, including suggestions on the possible ways to organise image resources to ensure that they are unique. |
Sorry, I needed to clarify something about the logs, the previous message didn't have full details.
Important to note that I didn't test the behaviour of calling addSpriteFrameWithFiles despite isSpriteFramesWithFileLoaded being true. Also, I have checked all resources, image1.png is only present in game.plist. Can some other commonly named sprite frame cause this undefined behaviopur? Please let me know if there could be any other reason or any hypos, it will help me to debug further. |
How many frames are in that sprite sheet? Are you certain that there are no duplicate names across any of the sprite sheets? I've tried so many different combinations of purging via I've been trying to find any possible way that If you get rid of the call to |
There are around 300 sprite sheets, which on average have 10 sprite frames per sprite sheet. I haven't check for duplicates across all 3000 frames, but I have checked for the problem causing sprite frame "image1.png", it is just present in single sprite sheet (game.plist). The application uses around 700MB RAM on high resolution devices, the purge signal is not very frequent but the crash seems to have affected around 0.5% of the users. We are planning to add logs during purge signal to verify the link between image1.png and game.plist. The hypo is that, _spriteFrameToSpriteSheetMap["image1.png"] may not be pointing to game.plist. Any other ideas on what could be wrong? Also, I wanted to know, why did axmol take decision of removing unused sprite frames from cache even when texture is present in the memory. These sprite frames could be used without any extra load of reading from disk. Should the removeUnusedSpriteFrames flow be like, removing sprite frames from cache only if all of the sprite sheet's frames are unused. Basically, only when the texture can be released. |
This isn't a change in Axmol, since the code has been in there from at least Cocos2d-x v3, as you can see here: https://github.com/cocos2d/cocos2d-x/blob/e4b6a5ef8fcdc99a7ebea606312b67fe4c534b9f/cocos/base/CCDirector.cpp#L699 If you suspect that the behavior of the code has changed in some way since Cocos2d-x, then it's best to always check. There are some changes related to the frame cache, and perhaps there is a subtle bug in there, or it could be that the changes have brought an existing bug to light which is in either the engine or the project, but it's difficult to track down without some way to reproduce it. |
Can you please explain the theory regarding Previously, you've noted that the following returns null:
The implementation is as follows:
and
@halx99 Out of curiosity, is there any chance at all that the hash map implementations would end up with hash value collisions? I just noticed that they were changed from this:
to this:
I'm not familiar with the |
Is it possible to manually trigger the purge signal from the Android OS for testing? Just so it goes through the same code path. Also, if it's possible, make the
|
Since
We have tried to repro it this way, but we were not able to repro the crash.
Yeah, this we can do. But any idea on why/when this method's behaviour could be out of sync with SpriteFrameCache::getInstance()->getSpriteFrameByName(string_view)? |
Sorry, I still don't quite follow. What do you mean by "when image1.png was removed"? How is it removed? Are you able to show example code, or even pseudo code, to explain the scenario you're describing? I'm trying to understand the sequence of calls to achieve what you're describing. If you're implying that "image1.png" belongs to a different sprite sheet, and then that sprite sheet, or frame, is removed before attempting to use "image1.png" from a sprite sheet that should still be in memory, then that brings us back to the point of requirement of having unique names across all sprite sheets, which was mentioned in a previous post. You already mentioned that "Image1.png" is unique, so this should not be the issue. If you mean that "image1.png" is an individual file, and it is removed, then that should not affect anything, because individual image files are not added to the I've added more tests to the cpp-tests project in the attempt to create as many possible scenarios that could trigger an issue, including one that involves calling |
There are multiple crashes where the spriteFrameCache is unable to find a spriteFrame.
This only happens when android app receives onTrimMemory signal, on which I am calling Director::purgeCacheData method using mGLSurfaceView.queueEvent. This only happens in android and I am unable to repro the crash on my device.
I am calling the SpriteFrameCache::addSpriteFramesWithFile method with the plist name in which the spriteFrame belongs, right before calling Sprite::setFrameFrame. Can there be any reason why SpriteFrameCache::addSpriteFramesWithFile method would fail? Should axmol return error in such cases?
The text was updated successfully, but these errors were encountered: