Welcome, Guest
Want to take part in these discussions? Sign in if you have an account, or apply for one below
-
- CommentAuthoraudas
- CommentTimeAug 5th 2008 edited
The main problem with the entire flint particle system is its cleaning up. Having built many projects using the system I can safely say this is its greatest flaw. its simply destroys processors (2 gig of ram twin processor) is being crucified as I type.
emitter.dispose();
renderer.dispose();
do not appear to be working, (renderer appears to throw errors).
There was a brief post relating to looping through the Objects of a renderer and Emitter - although any information relating to how to acheive this was not forth coming. It then appeared that yes indeed there are bugs relating to this, and the demos were wrong, but fixed........
In short can we please have some information on how to deal with cleaning up the memory - this is an absolute deal breaker - can not work with this project at all as it stands and STRONGLY recommend no movement is taken into other areas (3d) until such fundamental issues are cleared up.
Have been working with this project since its inception - and the work arounds to deal with this issue are horrendous.
I look forward to hearing your thoughts on this as I very much like using the project and have some great stuff going on with it.
Cheers,
audas, -
- CommentAuthoraudas
- CommentTimeAug 5th 2008 edited
Further - the demo indicates that an action or an activity should be added as an instantion - how then do we find out what actions are on the emitter ?
Um - we cant clean up.
Do we make references to each action, add it to the emitter, store it an array, loop through that array check if it exists, and remove it ....wow - something wrong with emitter.destroy();?????
This as mentioned is an absolute deal breaker .... -
- CommentAuthorchien
- CommentTimeAug 5th 2008
Good questions! I am having problems in that exact same area. How to best get rid of an emitter and clean up?
chien -
- CommentAuthoraudas
- CommentTimeAug 5th 2008
It is a deeeep mystery......
These objects exist in memory but without any reference.....wont get collected by garbage collector.
Really confusing.
Some help on this would be really appreciated. -
- CommentAuthoraudas
- CommentTimeAug 5th 2008
Removing the EMITTER and the RENDERER do not remove everything from memory.
Removing them from the display list is also ineffectual.
The mystery . . . . -
- CommentAuthoraudas
- CommentTimeAug 5th 2008
Any chance on this anyone - -
- CommentAuthoraxel012345
- CommentTimeAug 5th 2008
Hi everybody :)
Maybe you don't see the memory collected because the garbage collector don't run itself, normally the garbage collector run just if need , so after some action that require memory.
I use them too and have no problem of lack memory visible. -
- CommentAuthoraudas
- CommentTimeAug 5th 2008
Nope I have narrowed it down to using the BitmapRenderer. Everything else operates as it should except this...... -
- CommentAuthoraudas
- CommentTimeAug 5th 2008 edited
Yep this is definitely where the problem lies - the BitmapRenderer is not working. It doesn't really matter how few DisplayObjects are put into it etc- it simply sends the CPU off the dial - this is only occuring with this renderer...
here is the code
emitterb = new Emitter();
emitterb.counter = new TimePeriod(5, 2);
emitterb.addInitializer(new Lifetime(1.5));
emitterb.addInitializer(new Velocity(new BitmapDataZone(bitmapData, -100, -100)));
emitterb.addInitializer(new Position(new BitmapDataZone(bitmapData)));
emitterb.addInitializer(new ImageClass(RadialDot, 7));
emitterb.addAction(new DeathSpeed(5, true));
emitterb.addAction(new Fade(.2, 0));
emitterb.addAction(new Age(Quadratic.easeIn));
emitterb.addAction(new RandomDrift(20, 20));
emitterb.addAction(new Move());
emitterb.addAction(new LinearDrag(1));
emitterb.addAction(new Accelerate(0, -5));
emitterb.addAction(new ColorChange(0xFFFFFFFF, 0x00000000));
emitterb.addAction(new Scale(1, 5));
emitterb.addAction(new DeathZone(new RectangleZone(-200, -200, 750, -50), false));
rendererb = new BitmapRenderer(new Rectangle(-200, -200, 750, 750));
rendererb.addFilter(new BlurFilter(5, 10, 1));
emitterb.renderer = rendererb;
addChild(rendererb);
emitterb.start();
TweenMax.to(this, 2, {alpha:0, onComplete:clear, delay:1});
let me know how you get on with this Richard would be interesting to see - basically it means SMOKE is out..... -
- CommentAuthorRichard
- CommentTimeAug 5th 2008 edited
Hi
I simplified your code a little - didn't want to have to check the TweenMax library for memory leaks. Also, I don't have the bitmap you're using. Here's the code, with clean-up on mouse click.package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.net.LocalConnection;
import org.flintparticles.actions.*;
import org.flintparticles.counters.*;
import org.flintparticles.displayObjects.RadialDot;
import org.flintparticles.emitters.Emitter;
import org.flintparticles.initializers.*;
import org.flintparticles.particles.ParticleCreator;
import org.flintparticles.renderers.*;
import org.flintparticles.zones.*;
public class FlintTest extends Sprite
{
private var emitterb:Emitter;
private var rendererb:BitmapRenderer;
public function FlintTest()
{
emitterb = new Emitter();
emitterb.counter = new Steady(5);
emitterb.addInitializer(new Lifetime(1.5));
emitterb.addInitializer(new Velocity(new PointZone( new Point( 100, 100 ))));
emitterb.addInitializer(new Position(new PointZone( new Point( 0, 0 ))));
emitterb.addInitializer(new ImageClass(RadialDot, 7));
emitterb.addAction(new Fade(1, 0));
emitterb.addAction(new Move());
rendererb = new BitmapRenderer(new Rectangle(-200, -200, 750, 750));
emitterb.renderer = rendererb;
addChild(rendererb);
emitterb.start();
stage.addEventListener( MouseEvent.CLICK, stopEmitter );
}
private function stopEmitter( ev:MouseEvent ):void
{
// remove all particles from the emitter - returning them to the particle factory
emitterb.dispose();
// clear all particles from the particle factory
ParticleCreator( emitterb.particleFactory ).clearAllParticles();
// remove the reference to the emitter
emitterb = null;
// remove the renderer from the stage
removeChild( rendererb );
// remove the reference to the renderer
rendererb = null;
// force the garbage collector to do its thing now - required for testing
try {
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:*) {}
}
}
}
This uses a trick from Grant Skinner to force the garbage collector to do a full mark and sweep - without this the garbage collector will only kick in when you need more memory. For a full clean up you have to remove the particles from the particle factory in the emitter - the particle factory stores references to dead particles so they can be reused. Without this line, everything else is removed but the particles remain for reuse by other emitters.
I ran this though the memory profiler in Flex Professional and afterwards only one Flint object remained in memory - the single static reference to the ParticleCreator that is used by all emitters and which, according to the profiler, requires 12 bytes of memory. There were no renderers, no bitmaps, no emitters, no actions, no initializers, no particles left in memory, and memory use by the application had dropped from 2290k to 74k.
EDIT: I removed the call to rendererb.dispose() because it turns out to be unnecessary - the BitmapData object will be garbage collected just like any other unreferenced object. -
- CommentAuthorRichard
- CommentTimeAug 6th 2008 edited
Just to clarify what's happening above...emitterb.dispose();
This causes the emitter to kill all particles and return them to the ParticleCreator for reuse. If you don't want to reuse the particles this isn't necessary. Without it, the particles currently used by the emitter will simply be garbage collected like other objects when the emitter itself is garbage collected.ParticleCreator( emitterb.particleFactory ).clearAllParticles();
This causes the ParticleCreator to delete all its particles so they can be garbage collected. You should only do this is you don't plan to create any more emitters, since reusing particles that the ParticleCreator is holding produces a significant speed boost to Flint. The particle creator is also in the protected static property _creator of all emitters. I think I should provide public access to this property so that you don't need to access it via an emitter instance. Look out for this update in a later version of Flint.
EDIT: removed reference to rendererb.dispose()emitterb = null;
If there are still references to the emitter, then it won't be garbage collected, so set any references to null.removeChild( rendererb );
rendererb = null;
Similarly, if there are still references to the renderer then it won't be garbage collected, so set any references to null. That includes the reference on the display list so remove the renderer from the display list.try {
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:*) {}
This simply forces garbage collection to occur immediately. It's not necessary in production systems unless you want to control when the garbage collection occurs. Without it, garbage collection will occur whenever the flash player decides it's necessary, which is usually when it's running out of memory.
Where memory leaks are likely to come from
EDIT: removed reference to BitmapRenderer.dispose()
The common source of apparent memory leaks is not clearing references to objects - the garbage collector will only delete an object if there are no references to it. If you don't clear the reference, the memory isn't strictly speaking 'leaked' because it's still accessible through the reference (and can be released later by clearing the reference). However, the effect is like a memory leak - your program uses more and more memory as it runs. References in arrays are cleared by removing items from the array, references in display lists are cleared by removing items from the display list, and references in variables or properties are cleared by assigning something else to the variable or, in the case of local variables defined inside a function, by exiting the function.
EDIT: added the following
The other common source for suspected memory leaks is not understanding how Flash's garbage collector works. The garbage collector only runs when it needs to. That is, when more memory is required. So, even if you remove all references to an object, it won't be removed from memory unless Flash needs the memory space the object is occupying. This is what the last piece of code is for - it forces the garbage collector to run now. It shouldn't be necessary in production code unless you want to control when the garbage collector will run, but it is necessary in testing code because without it we have no idea what memory is available for garbage collection and what is still in use. You can read more about the flash player's garbage collector here. -
- CommentAuthorchien
- CommentTimeAug 6th 2008
Thanks Richard that explains much. I think this is a very valuable post.
chien -
- CommentAuthoraudas
- CommentTimeAug 7th 2008
Adding to this :-
emiiter.addEventListener(FlintEvent.EMITTER_EMPTY, func);
MUST BE EXPLICITLY REMOVED.....
it appears that the event which fires on an EMITTER_EMPTY is not a one off event - rather - it is fired repeatedly and so calls to any associated function with the eventListener will be overridden by calls to the same function unless the listener is explicitly cleared.
I know most would automatically clean up after themselves but it got me ! -
- CommentAuthorRichard
- CommentTimeAug 7th 2008 edited
So, although Audas hasn't said it explicitly, the situation is- It wasn't a problem with cleaning up
- Emitter.dispose() works
- Renderer.dispose() works
- There are no bugs relating to this
- Everything is collected by the garbage collector if you remove all references to the emitters and renderers, including display list references
- This is not a problem that is specific to the BitmapRenderer
Which means the first message in this thread is totally inaccurate.
The problem was that Audas assumed that the EMITTER_EMPTY event only fired once, when in fact it fires whenever the emitter does an update and finds that it is empty. It stops if you pause the emitter, dispose of the emitter (to be renamed stop in a future version), or if the emitter creates more particles so it is no longer empty. -
- CommentAuthoraudas
- CommentTimeAug 7th 2008
Which is a perfectly reasonable assumption to make - the fact remains Richard that if you do not explicitly remove the event listener the function assigned to respond will continue to fire - this is very unclear and has caused users headaches along with mountains of lost time- rather than getting upset about it perhaps just make people aware that this is the situation.
Sure things were getting desperate and the fact that an emitter continues to fire once empty and has concluded its operations is in no way obvious and as you can see has consequences.
Deep breath mate. -
- CommentAuthorRichard
- CommentTimeAug 7th 2008
The emitter only concludes its operations when you stop it. If you ignore the event then the emitter will still try to update particles, find it has none, and send the event again. This is not an EMITTER_COMPLETE event, it is an EMITTER_EMPTY event and will continue to fire until you stop the emitter.
It sounds like you would prefer it if the emitter sent the event once and then never again. The problem with this is that some users use the event as a signal to modify the counter or to restart the emitter (see the LogoFirework example), not as a signal to remove the emitter as you are interpreting it. If the event is only sent once then these sort of behaviours aren't possible.
It seems to me that some counters (e.g. the TimePeriod counter) should send a COMPLETE event when they are done. The EMITTER_EMPTY event is fine as it is, although the documentation needs to be clearer. -
- CommentAuthoraudas
- CommentTimeAug 8th 2008
Richards Solution above works perfectly and is very simple to implement, just remove the listener from emtter
emitter.removeEventListener(FlintEvent.EMITTER_EMPTY, func);
then carry out any actions you need - you can then add the listener back on
emitter.addEventListener(FlintEvent.EMITTER_COMPLETE, func);
Alternatively for the advanced user you can implement a complete event - I have not thoroughly tested this and there may be issues with it but it seems ok for this version - Richard hope this is right ??!
To implement a complete then simply add the event to the FlintEvent
public static var EMITTER_COMPLETE:String = "emitterComplete";
Then add a complete Boolean to the Emitter:
private var complete:Boolean;
set complete to false in the start function
complete=false;
and then in the frameUpdate function simply check for the emitter being empty and add the conditional statement above it...
if(!complete){
dispatchEvent(new FlintEvent(FlintEvent.EMITTER_COMPLETE));
complete=true;
}
dispatchEvent(new FlintEvent(FlintEvent.EMITTER_EMPTY));
this will only be dispatched once - and when the emiiter is started again - it is reset.
Not sure how this will impact on multiple renderers on multiple emitters though in the next version. Could simply emit a complete event for each based on its name. -
- CommentAuthorRichard
- CommentTimeAug 8th 2008 edited
Audas - that sounds like it would work fine. Two things I'm considering before implementing something like this in the main code...
1. Would it be better to use the standard Event.COMPLETE event? Or should Flint always use its own custom events?
2. Should the event come from the emitter or the counter? An emitter is never truly complete - it is just waiting for the counter to tell it to emit more particles. Some counters, however, like the TimePeriod counter do reach a point where they have finished and so are complete. Sending the event from the counter (perhaps bubbling to the emitter too) feels better at the moment, but I'm not entirely sure so would welcome feedback from anyone.
1 to 18 of 18
