GithubHelp home page GithubHelp logo

Comments (31)

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Thanks for posting the very helpful example - I'm able to reproduce the memory leak here too.

I've had a scan through the clear()/draw() cycle, and I can't see any obvious object references building up anywhere. Scout reports the memory is being gobbled by actionscript objects (not bitmaps or 'other'), and the GPU memory usage is nice and stable.

If anyone reading this has got a 'Premium' copy of FlashBuilder, and could run this example through the memory profiler, that'd help me loads (AFAIK Scout doesn't give a detailed memory breakdown) . I'm hoping a particular class type sticks out like a sore thumb with a gazillion instances of it being reported.

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Ok - so this fixes around 90% of the leak. 7fb8463

Memory usage still rises inexorably, though much more slowly.

Turns out not nulling private members during dispose is 'a bad thing'. I always figured that if the only reference to an object was owned by an orphaned object, then this child object should also be GC'd - ie, it's 'unreachable' by any other code.

Also of note, I was able to slow the memory usage further by nulling some more references in starling's DisplayObject.

from starling-extension-graphics.

kerissakti avatar kerissakti commented on June 16, 2024

Yes I'm also having this issue, it seems that any Graphics object such as Fill & Stroke are not disposed properly after the clear() function is called. Something somewhere is still referencing to the objects so they are never GC'ed.
I'm using FB 4.6 AIR 3.6 ASC2

from starling-extension-graphics.

Sudarmin avatar Sudarmin commented on June 16, 2024

Hi,I think I've fixed the issues, basically I modified the Graphics.as, Graphic.as, NGon.as, Fill.as, Stroke.as
All in the graphics package
if you want to try it, you can download it here :
http://www.sendspace.com/file/0p82zd
or
http://www.2shared.com/file/fIq8YGam/starling.html
http://www.2shared.com/file/WKZMJjBy/starling.html

from starling-extension-graphics.

Selonie avatar Selonie commented on June 16, 2024

Sudarmin - I don't know what you've done but it seems to be working for me, memory drops back down to its initial level periodically. Thanks.

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Hey Sudarmin - great job! - I grabbed your RAR earlier and found a few of the files weren't changed at all, and Fill added a 'Texture' public property which it then nulled during dispose.

So I'm not entirely sure how to merge this in (is it possible you've got an older version of the project checked out?).

It's possible I've messed something up somewhere - I'll take another look tonight. Or just send me over a pull request if that's easier for you.

from starling-extension-graphics.

Sudarmin avatar Sudarmin commented on June 16, 2024

The most important part was in the "Graphic.as"
in the dispose() function, someone forgot to remove the event listener, which made the GC unable to collect it, so I added this in the dispose function :
Starling.current.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated);

I added the variable "texture" in graphic.as, because I saw when bitmapfill() was called in "Graphics.as", the texture that has been created from bitmapData did not get disposed properly (at least that is what I think), I forgot to submit the "Graphics.as", I modified a bit in there that made it more efficient, I think, I'll submit it tomorrow I don't have the file right now

from starling-extension-graphics.

Sudarmin avatar Sudarmin commented on June 16, 2024

So here it is the complete Display package that I modified, might not be the best practice out there but I hope it can help
http://www.sendspace.com/file/uv6m2y
http://www.2shared.com/file/dzh1TP-A/display.html

Thanks for creating this awesome extension though, cheers :)

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Aaah! That'll explain why this leak wasn't occurring in older versions (I only recently added support for handling a lost context). It also explains why my 'unreachable' objects were in fact still reachable.

Thanks for the new download - looks good. I'll take a proper look tonight and get the final fix in there ASAP.

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Ok, that's in.
f64b975

Thanks again!

from starling-extension-graphics.

wrench7 avatar wrench7 commented on June 16, 2024

There's still a memory leak somewhere in this extension. Not sure where at the moment, but hope to track down the culprit and will post when/if I find it.

from starling-extension-graphics.

wrench7 avatar wrench7 commented on June 16, 2024

Ok, I've tracked down the issue to endFill() removing the _currentFill from the _container which then means that it's not disposed off properly when the Shape is also disposed of. Commenting out the code below in endFill() fixes the memory leak (though am not sure if there's any other ramifications to leaving the _currentFill on stage, there doesn't appear to be as far as I can tell)

if ( _currentFill && _currentFill.numVertices < 3 ) {
_container.removeChild(_currentFill);
}

from starling-extension-graphics.

wrench7 avatar wrench7 commented on June 16, 2024

drawRoundedRect() without a fill being applied also leaks memory. drawRect without a fill doesn't however.

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Rather than commenting out, doing this should fix the first issue.

if ( _currentFill && _currentFill.numVertices < 3 ) {
_container.removeChild(_currentFill);
_currentFill.dispose();
}

As for the second issue, I'd wager it's because RoundedRectangle...
https://github.com/unwrong/Starling-Extension-Graphics/blob/master/extension/src/starling/display/graphics/RoundedRectangle.as

isn't overriding dispose() and null'ing its reference to 'strokePoints'.

I'll get a fix together tonight and let you know when it's in.

from starling-extension-graphics.

wrench7 avatar wrench7 commented on June 16, 2024

Wow, that was quick! I actually tried your first fix, but in the opposite order (dispose, then remove) and it causes a #1009 error in the drawTriangles() method of the StandardMaterial Class
context.setTextureAt( i, i < _textures.length ? _textures[i].base : null );

Same applies with the fix you've suggested so that may need to be looked into a bit more.

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Thanks for the extra info. I've got a handle on what the problem is.

It boils down to me trying to be a bit too clever with sharing materials between different graphics (the aim being to avoid the situation where 100 drawn rectangles are being draw with 100 different shaders) - Because of the sharing, we can't dispose a graphic and its associated material without some sort of reference counting to ensure no other graphic is currently using the same material.

It's a tricky fix, so I'm going to give it some thought before I pile in. Once in, it should patch both these leaks.

from starling-extension-graphics.

wrench7 avatar wrench7 commented on June 16, 2024

Hey Jonathan, any further thoughts on the memory leaks detailed above? Just a gentle nudge ;-)

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Nudge acknowledged!

I'm afraid my day job is sucking up most of my time at the moment - so haven't really been able to support this project as much as I would like lately. Work will be calming down around October - I'l be back in full force then.

from starling-extension-graphics.

IonSwitz avatar IonSwitz commented on June 16, 2024

Ah, shoot. Maybe this set of fixes will break this material sharing bit.

#58

Not having a good reproduction if the case with sharing materials, it's hard for me to determine if it is even possible to solve both problems here.

from starling-extension-graphics.

jonathanrpace avatar jonathanrpace commented on June 16, 2024

Leak fixed
853c941

Note: This is quite a big refactor. Resource management is now much more sane, however this has come at the expense of beginBitmapFill() - use beginTextureFill() instead.

Allowing the API to create textures for you is just asking for abuse. I'm guessing everyone here is already very protective over how and when they create their Textures anyway, so won't mind this slight inconvenience.

from starling-extension-graphics.

IonSwitz avatar IonSwitz commented on June 16, 2024

Nice work.

The one issue with removing the beginBitmapFill is the aim to have functionality that allows a direct import of graphicsData from flash readGraphicsData:

starlingShape.graphics.drawGraphicsData(flashShape.graphics.readGraphicsData());

But maybe that can be worked around, somehow turning a bitmapFill into a textureFill for this type of work.

I will grab your latest awesomeness and see what can be done to keep this otherwise pretty neat functionality (currently in the IonSwitz fork)

See #66 for further discussion, perhaps?

from starling-extension-graphics.

LiuWong avatar LiuWong commented on June 16, 2024

Memory leaks as before.

package test
{
    import starling.display.DisplayObjectContainer;
    import starling.display.Shape;
    import starling.display.Sprite;
    import starling.events.EnterFrameEvent;
    import starling.events.Event;
    import starling.textures.RenderTexture;
    import starling.utils.getNextPowerOfTwo;

    /**
     * ...
     * @author Liu Wong
     * 
     */

    public class testLeak extends Sprite
    {
        private const deltatime:int = 1;
        private var counter:int = 0;

        private var item:Shape;

        private var texture:RenderTexture;

        public function testLeak(prnt:DisplayObjectContainer):void
        {
            super();

            prnt.addChild(this);

            texture = new RenderTexture(128,128);

            addEventListener(EnterFrameEvent.ENTER_FRAME, onUpdate);
        }

        private function onUpdate(event:Event):void
        {
            counter++;

            if (counter >= deltatime)
            {
                counter = 0;

                if (item == null)
                {
                    item = new Shape();
                    addChild(item);
                }
                else
                {
                    var tmp:Shape = new Shape();
                    tmp.graphics.lineStyle(1, 0xff0000);
                    tmp.graphics.beginTextureFill(texture);
                    tmp.graphics.drawRect(0, 0, 32, 32);
                    tmp.graphics.endFill();
                    addChild(tmp);
                    tmp.x = Math.random() * 300;
                    tmp.y = Math.random() * 300;

                    item.graphics.clear();
                    item.removeFromParent();
                    item.dispose();

                    item = tmp;
                }
            }
        }
    }

}

from starling-extension-graphics.

IonSwitz avatar IonSwitz commented on June 16, 2024

I can look into this, to find a solution here, but first I would like to know what it is that is leaking.

What objects don't get cleared in this scenario?

from starling-extension-graphics.

LiuWong avatar LiuWong commented on June 16, 2024

I can not say what it was, but the built-in Starling debug stats - showing the volume of used memory, demonstrates the rapid growth in this simple example.

from starling-extension-graphics.

neolit123 avatar neolit123 commented on June 16, 2024

probably related to 6aa243b?
Graphics and Shape need proper dispose methods.

from starling-extension-graphics.

IonSwitz avatar IonSwitz commented on June 16, 2024

I have checked in a dispose method on the Graphics class. The functionality can't be added to the regular "clear" method without hurting backwards compatibility, so I added a separate code path for this.

Please try it out.

instead of: item.graphics.clear() do item.graphics.dispose()

adding the Graphics.dispose() method to Shape.dispose() would unfortunately hurt backwards compatibility

I ran the sample for 5 minutes, and it kept returning to the same lowest level of memory usage after garbage collects

from starling-extension-graphics.

neolit123 avatar neolit123 commented on June 16, 2024

thanks for looking into this,

given Shape is a top level class and it's sole purpose is to extend DisplayObjectContainer and encapsulate Graphics, i wonder what backwards compatibility it breaks to have a dispose() method in Shape that calls Graphics::dispose(). it just seems logical to have it...

if the BC issue is related to double "diposal" of sorts calls, this can be easily solved with a simple "isDisposed" flag and solve the compatibility in the mean time.

perhaps this should be reconsidered?

(edit: of course the idea would be to not force the user to explicitly call someShape.graphics.dispose() each time)

from starling-extension-graphics.

IonSwitz avatar IonSwitz commented on June 16, 2024

The issue is that the behavior would change. In the current "clear" call, the Strokes aren't disposed, and it is not impossible to have a use case that would change it's behavior if the dispose call was included in the call to clear.

I would rather implement this in a way that makes the old behavior remain the same, and the dispose method for the explicit call. If I had more time to spend on the Extension, I agree that your approach is better, but I am unable to devote time to the project and therefore I prefer to make the risk lower that I break old implementations by changing the existing behavior.

Recreating shapes every frame is, in general, not recommended at all. The example with the drawRect is not that heavy, but replacing it with a drawCircle call makes the code a LOT slower.

from starling-extension-graphics.

neolit123 avatar neolit123 commented on June 16, 2024

The issue is that the behavior would change. In the current "clear" call, the Strokes aren't
disposed, and it is not impossible to have a use case that would change it's behavior if the
dispose call was included in the call to clear.

can you better explain how exactly the backwards compatibility is affect by adding _graphics.dispose() in Shape::dispose()? are you suggesting the usecase where the user creates a Graphics instance, calls dispose() on it and then attempts to call other API methods such as clear() on the same instance, where the textures are already disposed of?

perhaps i can give it a try, but i'm finding trouble understanding the BC issue.

from starling-extension-graphics.

IonSwitz avatar IonSwitz commented on June 16, 2024

The main point is that I don't have the time to investigate it, and I don't have time to work on patches if changing the dispose method breaks other behavior in already existing code using the SEG.

So I would prefer to use a separate method call to be on the safe side.

Writing an API is hard as hell, as concern has to be taken not just with internal consistencies but with the code that others have written that use these classes. For example, the extended Shape and Graphics classes, ShapeEx and GraphicsEx is just one example of code that might run into problems if the behavior of dispose() changes.

But, as I said, the main reason for not changing the current behavior is an extreme lack of time.

If you wish to investigate the consequences further, feel free. I would be very grateful.

from starling-extension-graphics.

neolit123 avatar neolit123 commented on June 16, 2024

thanks for the answer,

So I would prefer to use a separate method call to be on the safe side.

i will take your overview as a good indication that the explicit graphics.dispose() is safer and "should suffice" at this point.

extreme lack of time

ditto on my end pretty much, which makes it very tempting not to investigate at all.

from starling-extension-graphics.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.