Jump to content
Search Community

Is Transform object made by gsap and how do I destroy it?

milos98 test
Moderator Tag

Recommended Posts

I am referring to highlighted item in memory snapshot:

1087603073_Screenshotfrom2022-02-2807-14-23.thumb.png.c0d276810de22a4b1c522739c81de90c.png

 

I'm making Slot machine using typescript, webpack, pixijs and gsap.  I'm using gsap to animate spinning of the reels. After every spin, my app takes more and more memory and I think it is because of gsaps caching. I am using one timeline as animation sequencer, to which I'm adding individual animations of every reel. 

 

For every reel I implemented spinning as such: 

init new timeline

make very long reel (to existing 3 slots i append N slots on top)

add animation for that reel (just move it down for N positions)

append timeline to animationSequencer (main timeline)

crop slots array so that only final 3 remain 

 

animationSequencer is paused on creation and only played after all animations are queued as such:

dataController.animationSequencer.play('spinReels').then(() => {
            dataController.animationSequencer.kill()

            dataController.animationSequencer= gsap.timeline({ paused: true })
        })

 

I also tried adding dataController.animationSequencer.invalidate() before kill() but with no success. 

 

So my question is: if I want to ensure that nothing that gsap has animated is in cache, how do I do it? Does kill on animationSequencer propagate on all it's children? Does invalidate propagate?

 

If Transform is not gsap created object than I'm sorry for my mistake.

 

Link to comment
Share on other sites

Welcome to the forums @milos98

 

Transform is a PixiJS class, which calculates stuff like x, y, and scale.

 

It's also not clear if you creating a new animationSequencer timeline. From your description it kind of sounds like you are just adding to, which will of course make it longer, keeping more objects in memory.

 

For the record, kill does not clear objects from memory. It just makes them available for garbage cleanup, but only if there are no references to the object. For example, this will still keep the animation in memory because I have a variable referencing it.

 

let animation = gsap.to(mySprite, {
  x: 100
});

// makes it available for cleanup...
animation.kill();

// ...but the animation object is still being referenced so still in memory
console.log(animation)

 

To free up the reference I would need to null it out.

let animation = gsap.to(mySprite, {
  x: 100
});

// makes it available for cleanup
animation.kill();

// now it can be removed when the browser does its garbage collection
animation = null;

 

If you're using the same timeline over and over again, you should probably clear it before adding a new animations.

 

  • Like 2
Link to comment
Share on other sites

Hello, thanks for quick response. 

 

Is this:

dataController.animationSequencer.kill()
dataController.animationSequencer = gsap.timeline({ paused: true })

not the same as this? Does it not assign new instance of timeline to animationSequencer and destroys old one?

dataController.animationSequencer.kill()
dataController.animationSequencer = null
dataController.animationSequencer = gsap.timeline({ paused: true })

 

I tried with this first, but still got memory leaks:

dataController.clear()

My timeline works properly in both cases (animation runs as predicted), but Transform objects are still piled on in memory, that's why I tried using invalidate too. There is no other place where I'm referencing animated stripes, so only suspect left is gsap.

 

This is the way I'm adding animations to animationSequencer:

public queueReelAnimation(aditionalStripes: number, animationDelay: number, someOtherArgs){
	const reelTimeline = gsap.timeline()
	for (let i = 0; i < aditionalStripes; i++) this.insertStripe()

	reelTimeline.to(...)	//1st part of animation
		.to(...)	//2nd part of animation
		.to(...)	//3rd part of animation

	this.stripes = this.stripes.slice(1, 4)
	dataController.animationSequencer.add(reelTimeline, `<${animationDelay}`)
}

 

On the side note, I would prefer to use kill instead of clear because I'm adding events to be triggered at certain point in animation. In docs I didn't find that clear removes those events from timeline and I want to be certain that they are gone. I'm adding events using .call(function, args, time).

 

Link to comment
Share on other sites

1 hour ago, milos98 said:

Is this:

dataController.animationSequencer.kill()
dataController.animationSequencer = gsap.timeline({ paused: true })

not the same as this? Does it not assign new instance of timeline to animationSequencer and destroys old one?

dataController.animationSequencer.kill()
dataController.animationSequencer = null
dataController.animationSequencer = gsap.timeline({ paused: true })

 

 

Should be, but what are you callbacks doing? Is there something running in those?

 

1 hour ago, milos98 said:

but Transform objects are still piled on in memory, that's why I tried using invalidate too. There is no other place where I'm referencing animated stripes, so only suspect left is gsap.

 

Like I said earlier, Transform is a PixiJS class, and GSAP does not touch it directly. Every DisplayObject in PixiJS, like a Sprite uses that class.

 

http://pixijs.download/release/docs/PIXI.DisplayObject.html#transform

 

http://pixijs.download/release/docs/packages_math_src_Transform.ts.html

 

Your snapshot shows a bunch of Sprites too so I'm not sure that number of Transform objects is too surprising. If you think it is is a memory leak, you may want to raise an issue with PixiJS.

 

Link to comment
Share on other sites

30 minutes ago, OSUblake said:

Should be, but what are you callbacks doing? Is there something running in those?

My callbacks are running simple logic, like set some button's interactive property to false etc. Nothing related to timelines or Sprites.

 

31 minutes ago, OSUblake said:

Like I said earlier, Transform is a PixiJS class, and GSAP does not touch it directly. Every DisplayObject in PixiJS, like a Sprite uses that class.

Could it be that gsap is storing (in memory) objects it is animating and that's why I have problem? Even if nothing else is referencing them?

 

Will this for sure delete all Sprites from memory?

let sprites = []
sprites.push(Sprite.from(source1))
sprites.push(Sprite.from(source2))

let timeline = gsap.timeline({ paused: true })

timeline.to(sprites, pixi:{
            x: 300
            })

sprites = []
await timeline.play()
timeline.kill()
timeline = gsap.timeline()

 

Does kill on parent timeline invoke kill on it's children timelines? And if so, if I set main timeline to null does that guarantee that all initiated objects are deleted?

 

Link to comment
Share on other sites

21 minutes ago, milos98 said:

Will this for sure delete all Sprites from memory?

 

You should probably destroy your sprites first before clearing the array, but everything else looks fine.

 

http://pixijs.download/release/docs/PIXI.Sprite.html#destroy

 

If you believe there is memory leak in GSAP, can you provide a minimal demo that clearly illustrates the problem? Also keep in mind that objects may not be immediately garbage collected. GSAP releases objects every around every 2 seconds, but the browser determines when they actually get removed from actual memory.

 

Link to comment
Share on other sites

37 minutes ago, OSUblake said:

If you believe there is memory leak in GSAP, can you provide a minimal demo that clearly illustrates the problem?

 

Also, I would try a comparison without using the PixiPlugin. For example, you really don't need to use the plugin if you are animating x or y.

 

timeline.to(sprites, { pixi: { x: 300 }})

// vs
timeline.to(sprites, { x: 300 })

 

And for good measure, try an animation without using GSAP.

app.ticker.add(() => {  
  sprites.forEach(sprite => {
    sprite.x += 0.1
  });
})

 

Link to comment
Share on other sites

4 hours ago, OSUblake said:

You should probably destroy your sprites first before clearing the array, but everything else looks fine.

Mistake was on my part. 

So pixijs uses webGL and it uses GPU for processing. What I didn't know is that you have to clean GPU memory by yourself because it won't be emptied by garbage collector, sooo I was missing sprite.destroy(). 

Destroying objects is recommended only in applications that are running for a long time, such as slot games :) 

 

Love your product, forum and support. Thanks a LOT for help.

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...