SafeDeleting an animated sprite doesn't seem to free resources?
by Teck Lee Tan · in Torque Game Builder · 09/19/2005 (1:28 am) · 13 replies
I noticed an odd thing today as I was playing with the firing code in the little game I've been tinkering with. Right now I'm using an animated sprite for the bullets/tracers, and it's working nicely as far as visuals as well as how I'm handling the actual gameplay side of things. The only problem is that it seems safeDeleting the sprite doesn't actually free up any resources.
I've got safeDelete() getting called in the onAnimationEnd callback, and all seemed okay until I realized that my mem usage was steadily increasing as I continued firing, and didn't drop back down when I stopped. Also, after a period of firing, my framerate starts going to hell. I tried using delete() as well, but that didn't have any appreciable improvement.
My firing code currently spawns a new fxAnimatedSprite2D with each shot, and then safeDelete() once the animation is done playing. Is there any way to ensure the bullets are completely destroyed and no longer take up any resources?
I've got safeDelete() getting called in the onAnimationEnd callback, and all seemed okay until I realized that my mem usage was steadily increasing as I continued firing, and didn't drop back down when I stopped. Also, after a period of firing, my framerate starts going to hell. I tried using delete() as well, but that didn't have any appreciable improvement.
My firing code currently spawns a new fxAnimatedSprite2D with each shot, and then safeDelete() once the animation is done playing. Is there any way to ensure the bullets are completely destroyed and no longer take up any resources?
#2
With the issue outlined above, the memory usage wasn't really the issue, though, just something that spurred me to test what was going on by firing a whole hell of a lot of bullets. Since each sprite is an 8-frame animation of 8x8 pixels, the memory usage is nowhere near worrying. What was bugging me, though, was the performance hit over time.
Could you possibly explain the bit about "creating bursts of a set quantity?" I'm not entirely clear on what you meant by that.
Here's the relevant code I'm currently using:
09/19/2005 (5:41 am)
Thanks for the explanation, that helped me understand some.With the issue outlined above, the memory usage wasn't really the issue, though, just something that spurred me to test what was going on by firing a whole hell of a lot of bullets. Since each sprite is an 8-frame animation of 8x8 pixels, the memory usage is nowhere near worrying. What was bugging me, though, was the performance hit over time.
Could you possibly explain the bit about "creating bursts of a set quantity?" I'm not entirely clear on what you meant by that.
Here's the relevant code I'm currently using:
function fxSceneObject2D::shoot(%this, %target)
{
if($mouse0)
{
if($shotcount > 1 && !$burst)
{
$burst = true;
$burstloop = alxPlay(burstloop);
}
//
//bunch of calculations for the bullets
//
%bullet = new fxAnimatedSprite2D() { sceneGraph = t2dSceneGraph; };
%bullet.tag = "bullet";
%bullet.setPosition(%sourcePos);
%bullet.setRotation(%angle);
%bullet.setSize(0.5 SPC (%distance * 2));
%bullet.playAnimation(traceranim);
%this.schedule(33, "shoot", %target);
}
}
function fxAnimatedSprite2D::onAnimationEnd()
{
if(%this.tag $= "bullet")
{
%this.safeDelete();
}
}
#3
Presumably you've looked at the scene object count in the debug-info and this is just a typo?
EDIT: I just tried a modified version of your code and it works fine in you change the callback to be "onAnimationEnd(%this)" otherwise the objects are not being deleted.
- Melv.
09/19/2005 (7:33 am)
I've not tested this code yet in v1.0.2 but something I noticed (that may just be a typo) is that the "onAnimationEnd()" is deleting the object using "%this" but you're not defining that variable so it looks like your objects won't be deleted.Presumably you've looked at the scene object count in the debug-info and this is just a typo?
EDIT: I just tried a modified version of your code and it works fine in you change the callback to be "onAnimationEnd(%this)" otherwise the objects are not being deleted.
- Melv.
#4
Nothing in the console log relating to the cause of the crash, either.
09/19/2005 (7:39 am)
No, the objects definitely get removed (at least from view). Interestingly enough, changing the function line tofunction fxAnimatedSprite2D::onAnimationEnd(%this)causes an immediate crash after firing the first shot (presumably at the first onAnimationEnd call). I'll have to take a look at the debug info, though, didn't think to do that.
Nothing in the console log relating to the cause of the crash, either.
#5
Hard to comment on the crash without further info.
- Melv.
09/19/2005 (7:45 am)
Well, if you didn't include the "%this", you objects were not being deleted by this code so you'll have huge quantities of objects causing the slowdown, even if they're not in the view.Hard to comment on the crash without further info.
- Melv.
#6
edit:
I'm officially an idiot. For some reason I had unwittingly changed .safeDelete() to .delete(). That's what was causing the crash. *sigh* All's good now. Thanks again, Melv! :)
09/19/2005 (7:51 am)
You're right, of course. Object count climbed steadily with no drop. I can't figure why including "%this" in the callback function is causing a crash, though. With the "%this", the syntax looks okay, no? Here's the animation datablock stuff, just in case.datablock fxImageMapDatablock2D(tracerframes)
{
mode = cell;
cellWidth = 8;
cellHeight = 8;
textureName = "~/client/images/traceranim";
};
datablock fxAnimationDatablock2D(traceranim)
{
imagemap = tracerframes;
animationFrames = "0 1 2 3 4 5 6 7";
animationTime = 0.25;
animationCycle = 0;
randomStart = 0;
};No errors anywhere, either, in the console log. :(edit:
I'm officially an idiot. For some reason I had unwittingly changed .safeDelete() to .delete(). That's what was causing the crash. *sigh* All's good now. Thanks again, Melv! :)
#7
Although there were a few fixes to the "safeDelete()" function that were causing crashes, they were upon exit during scene shutdown so it didn't seem to be what was happening here.
The callbacks are a sensitive area and "delete()" is pretty brutal. I might talk to Ben about the potential of making this a "safe" deletion and therefore remove the need for an explicit "safeDelete()" call.
Probably good you raised it. :)
- Melv.
09/19/2005 (9:46 am)
That's good to hear; glad it's working.Although there were a few fixes to the "safeDelete()" function that were causing crashes, they were upon exit during scene shutdown so it didn't seem to be what was happening here.
The callbacks are a sensitive area and "delete()" is pretty brutal. I might talk to Ben about the potential of making this a "safe" deletion and therefore remove the need for an explicit "safeDelete()" call.
Probably good you raised it. :)
- Melv.
#8
09/19/2005 (1:45 pm)
I always schedule deletions/safedeletions for 1 tick after so that they won't cause trouble. I found them to be very unstable if called immediately from within a callback, etc. (As already noticed, but just thought I'd concur.) :)
#9
Any problems with "safeDelete()" in v1.0.2 should have been resolve in v1.1.0.
- Melv.
09/20/2005 (7:24 am)
SafeDeletions are not unstable at all as the deletion happens prior to the scene-update, that's why they're safe. Standard deletions are definately not as they rip-out the underlying object which is disasterous inside the objects' callback. This is why I created the "safeDelete()" call so that you can call it anytime.Any problems with "safeDelete()" in v1.0.2 should have been resolve in v1.1.0.
- Melv.
#10
09/20/2005 (7:40 am)
Yeah, I recall seeing a blurb in one of the T2D docos discussing safeDelete() and delete(). Something about calling delete() in an object's callback being a really piss-poor idea. :)
#11
10/12/2005 (3:02 pm)
I kinda like safeDelete, hmmm it makes you feel....well...safe :)
#12
It's bad because even if you are not drawing a particular texture, it is still using up memory.
It's good because the texture is held within memory, and won't have to access the disk.
So in order to free the memory used by a texture you'll have to find a way to remove the datablock, which currently there is no way to do this in T2D. This is probably what you are seeing happen, the most, when deleting t2d objects from your scene. I'm not making any particular promises about this issue, but you can probably expect this kind of behavior to be improved on in the future.
On the project I'm working on currently I've hacked in a quick fix for this issue, so to give you an idea of how drastic this kind of behavior will be I'll give you some numbers. Using normal T2D my application used ~90mb memory on first load. After my changes my application used ~25mb memory on first load, and peaked ~65mb memory while in-game. My fix isn't perfect, as it was just a quick solution to a problem that needs to be thought through a little more before it will make it into T2D.
So, if you have the technical know-how and you want a quick solution, you can start by looking at the image map datablocks in C++ and change how the TextureHandle's are used.
10/12/2005 (3:58 pm)
SafeDeleting objects which have an associated image map, like a t2dStaticSprite or a t2dChunkedSprite for instance, won't free the texture memory. This is because the TextureHandle's reside in the image map datablocks, and not within the t2d objects themselves. This can be good and bad.It's bad because even if you are not drawing a particular texture, it is still using up memory.
It's good because the texture is held within memory, and won't have to access the disk.
So in order to free the memory used by a texture you'll have to find a way to remove the datablock, which currently there is no way to do this in T2D. This is probably what you are seeing happen, the most, when deleting t2d objects from your scene. I'm not making any particular promises about this issue, but you can probably expect this kind of behavior to be improved on in the future.
On the project I'm working on currently I've hacked in a quick fix for this issue, so to give you an idea of how drastic this kind of behavior will be I'll give you some numbers. Using normal T2D my application used ~90mb memory on first load. After my changes my application used ~25mb memory on first load, and peaked ~65mb memory while in-game. My fix isn't perfect, as it was just a quick solution to a problem that needs to be thought through a little more before it will make it into T2D.
So, if you have the technical know-how and you want a quick solution, you can start by looking at the image map datablocks in C++ and change how the TextureHandle's are used.
#13
It is possible to delete datablocks. You can do so like any other SimObject,
via the call %datablock.delete();
This will delete the datablock, and any memory associated with that datablock,
including texture space. Thus freeing up your resources.
You want to make absolutely certain however, that no t2dSceneObjects currently
exist are using the datablock you are trying to delete.
10/15/2005 (11:44 am)
I would like to clarify a statement I made in the previous post.It is possible to delete datablocks. You can do so like any other SimObject,
via the call %datablock.delete();
This will delete the datablock, and any memory associated with that datablock,
including texture space. Thus freeing up your resources.
You want to make absolutely certain however, that no t2dSceneObjects currently
exist are using the datablock you are trying to delete.
Associate Melv May
This shouldn't be too suprising as things such as "vectors" work in an identical manner e.g. as you "delete" the vector elements, the memory allocation stays and the element-count is adjusted only.
With reference to what's happening in your app; maybe you are encountering a problem (that more than likely has been fixed already) in T2D.
It might be wise to create a very simple script that creates bursts of a set quantity of objects then deletes them. The memory shouldn't continue to grow unbounded. If it does, you could send me the same script and I could check to see if the same problem exists.
This is probably the best I can do being as there's such a difference between the versions now. As simple a script as possible would be good.
- Melv.