You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@flex.apache.org by XaviConde <ja...@gruposame.com> on 2016/02/23 17:46:25 UTC

Memory leak caused by addChild() ?

Hi everyone,

I'm investigating memory leaks in an application, and since the codebase is
very complex, I've downloaded a simple project from
http://dreamingwell.com/articles/archives/2008/05/understanding-m.php to
understand what causes a memory leak and what doesn't. The Flash Builder
project can be found here:
http://dreamingwell.com/examples/flex/memoryleak/MemoryLeakTest.zip.

In short, despite I follow the instructions about how to 'fix' the sample
memory leak, the application still increases its memory usage.

These are the steps I follow:

1. Donwload
http://dreamingwell.com/examples/flex/memoryleak/MemoryLeakTest.zip.
2. Import into Flash Builder as a new project. It asks to update from Flex
Builder 3. I choose to use SDK 4.6.0.
3. Run Flash Profiler. Live Objects view shows the counts for
NonLeakySubComponent class increasing, and memory graph increases constantly
as well.
4. Uncomment `references.splice( references.indexOf(lastInstance),1);' from
LeakByReference.mxml:run(). This should fix the memory leak according to the
comments.
5. Run Flash Profiler. Live Objects view still shows the counts for
NonLeakySubComponent class increasing, and memory graph increases constantly
as well.
6. Comment this.addChild(subComponent) from LeakByReference.mxml:run().
Notice that there's a this.removeChild(subComponent) at the beginning of the
function.
7. Run Profiler. This time, only one instance of NonLeakySubcomponent is
displayed, and memory never increases.

I would like to understand why this.removeChild() is not freeing the
NonLeakySubComponent object, as it should (or why addChild() is creating a
strong reference to it which causes the GC not to free it after calling
removeChild()).

Thanks in advance.




--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: Memory leak caused by addChild() ?

Posted by Alex Harui <ah...@adobe.com>.

On 2/25/16, 4:33 AM, "XaviConde" <ja...@gruposame.com> wrote:

>After reviewing my 'fix', actually what was happening is that it was
>making
>the application crash, which is why the application memory was not
>increasing... 
>
>Anyhow I think there should be only 1 instance of NonLeakySubcomponent in
>memory at any time, irregardless of whether the GC would collect it or
>not.
>I'll keep on looking into it.

Well, it is my understanding that GC schemes (especially mark&sweep
schemes like Flash uses) rarely if ever promise that in these types of
scenarios there will only be one instance at any time.  I think you are
describing more of a reference counting scheme.  And what we recommend
when we talk about recycling renderers and object pooling is essentially
building your own reference counting scheme in ActionScript.

I've been told that there are at least two sets of objects for the sweep,
and if you do add more code to remove all children and other circular
references, you might find that your object ends up in the first set and
gets GC'd before the GC runs out of time and stop sweeping.  Things with
circular references supposedly take longer to be swept, even though the
circular references really should be slowing the mark phase.

HTH,
-Alex


Re: Memory leak caused by addChild() ?

Posted by XaviConde <ja...@gruposame.com>.
After reviewing my 'fix', actually what was happening is that it was making
the application crash, which is why the application memory was not
increasing... 

Anyhow I think there should be only 1 instance of NonLeakySubcomponent in
memory at any time, irregardless of whether the GC would collect it or not.
I'll keep on looking into it.



--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677p51729.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: Memory leak caused by addChild() ?

Posted by XaviConde <ja...@gruposame.com>.
Hi Alex, Clint,

I've finally reproduced the behaviour that you mention, only that I've had
to set the timer to 10 seconds. In that situation, forcing a garbage
collection from profiler frees some instances, so the number of total
instances is lower than Cumulative instances, without changing the code. So
you're right, instances get eventually freed by GC. (However using smaller
timer intervals still show me an equal number of cumulative instances and
instances and memory increasing indefinitely, even forcing a garbage
collection.)

However it still worries me the apparent behaviour of this simple
application. It would be better to actually remove the object reference that
is causing the instance to stay in memory so it is effectively removed. I
guess it is not immediately removed because there's a circular reference,
which makes the GC to not remove it quickly. With my 'fix' I'm removing the
circular reference, hence Flash Profiler reports only 1 instance of
NonLeakySubcomponent ever and memory stays constant, otherwise objects
accumulate in memory until GC eventually collects them.

Regards!



--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677p51728.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: Memory leak caused by addChild() ?

Posted by Alex Harui <ah...@adobe.com>.

On 2/24/16, 10:13 AM, "Clint M" <cm...@gmail.com> wrote:

>I was able to reproduce the behavior while using the references array and
>uncommenting the line:
>
>references.splice( references.indexOf(lastInstance),1);
>
>It might be that Player holds a reference to the object spliced out
>because
>it does return it.

I can use the reference array and splice out the last instance and again,
at 1 second intervals, hitting the GC button does free up the instances.

How much garbage builds up before it gets collected does have to do with
how memory is used and frame rates and how busy the player is doing other
things, but the key thing is that it will get GC'd eventually.

-Alex


Re: Memory leak caused by addChild() ?

Posted by Clint M <cm...@gmail.com>.
I was able to reproduce the behavior while using the references array and
uncommenting the line:

references.splice( references.indexOf(lastInstance),1);

It might be that Player holds a reference to the object spliced out because
it does return it.

In any case... I'd like to reiterate that it doesn't leak.

It's just doing what Alex describes as out-run the GC because it's calling
initialize on the sub component.

Here's a screen shot from my system when I set the frame rate to 60 and the
timer to 50ms.

https://www.dropbox.com/s/1suqwzkc2scewph/Screenshot%202016-02-24%2008.05.37.png?dl=0

On Wed, Feb 24, 2016 at 9:58 AM, Alex Harui <ah...@adobe.com> wrote:

> I removed the references array, slowed the timer down to 1 second and
> found that if I hit the GC button in the profiler, the instance count goes
> back to 1 or 2, which is correct, so NonLeakySubComponent is not leaking,
> without having to delete layoutObject.  Make sure you are looking at
> instance count and not cumulative instances?
>
> It is possible to "out-run" or "overload" the GC.  GC is trying hard not
> to interrupt animation and isn't guaranteed to do a full sweep.  If you do
> need to create and dispose of lots of instances of something, recycling
> old instances is likely to be worth the effort.  That's why item renderers
> are recycled in MX list controls.
>
> HTH,
> -Alex
>
> On 2/24/16, 9:15 AM, "Alex Harui" <ah...@adobe.com> wrote:
>
> >I took a quick look at the test case (I haven't even tried it in the
> >profiler yet).
> >
> >I assume the test case to run is LeakByReference.mxml.  In the run()
> >method, it keeps storing references to the new NonLeakySubComponent on
> >every pass, so sure, if you don't splice out the references to the old
> >ones, the references array is going to cause a memory leak.
> >
> >Are you saying if you are seeing a memory leak if you don't use the
> >references array?
> >
> >-Alex
> >
> >On 2/24/16, 8:27 AM, "XaviConde" <ja...@gruposame.com> wrote:
> >
> >>Hi Clint,
> >>
> >>Flash Profiler has a functionality to force garbage collection. I press
> >>the
> >>button several times and there's no instance being freed. Besides, taking
> >>a
> >>memory snapshot also forces garbage collection.
> >>
> >>On the other hand, after several hours of Flash Profiling, I have found a
> >>workaround by removing the property layoutObject:
> >>
> >>                      private function
> removedFromStage(event:Event):void {
> >>                              /* For good measure, the eventListener is
> removed when no longer
> >>needed
> >>*/
> >>
> parentApplication.removeEventListener(MouseEvent.CLICK,
> >>mouseClickEvent);
> >>
> >>//Stops memory leak
> >>                              this["layoutObject"]=null;
> >>                      }
> >>
> >>By removing this property (which held a CanvasLayout object added
> >>dynamically) now the memory usage is stable and Profiler never reports
> >>more
> >>than 1 instance of NonLeakySubcomponent ever in memory.
> >>
> >>For what I've learned from this example, calling initialize on the child
> >>object being added creates several objects which reference the child
> >>object
> >>itself. But when removeChild() is called, some of these circular
> >>references
> >>still exist. By forcing the removal as I've done it seems the circular
> >>reference is broken.
> >>
> >>I think it should be considered a bug, since removeChild() is not undoing
> >>all the actions of addChild(). I'm not sure if by letting it run enough
> >>time
> >>GC would remove the leaked instances; forcing the garbage collection from
> >>Flash Profiler has not removed them, or the related objects. This is
> >>happening on the latest 4.6.15 SDK.
> >>
> >>
> >>
> >>--
> >>View this message in context:
> >>
> http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-b
> >>y
> >>-addChild-tp51677p51715.html
> >>Sent from the Apache Flex Development mailing list archive at Nabble.com.
> >
>
>

Re: Memory leak caused by addChild() ?

Posted by Alex Harui <ah...@adobe.com>.
I removed the references array, slowed the timer down to 1 second and
found that if I hit the GC button in the profiler, the instance count goes
back to 1 or 2, which is correct, so NonLeakySubComponent is not leaking,
without having to delete layoutObject.  Make sure you are looking at
instance count and not cumulative instances?

It is possible to "out-run" or "overload" the GC.  GC is trying hard not
to interrupt animation and isn't guaranteed to do a full sweep.  If you do
need to create and dispose of lots of instances of something, recycling
old instances is likely to be worth the effort.  That's why item renderers
are recycled in MX list controls.

HTH,
-Alex

On 2/24/16, 9:15 AM, "Alex Harui" <ah...@adobe.com> wrote:

>I took a quick look at the test case (I haven't even tried it in the
>profiler yet).
>
>I assume the test case to run is LeakByReference.mxml.  In the run()
>method, it keeps storing references to the new NonLeakySubComponent on
>every pass, so sure, if you don't splice out the references to the old
>ones, the references array is going to cause a memory leak.
>
>Are you saying if you are seeing a memory leak if you don't use the
>references array?
>
>-Alex
>
>On 2/24/16, 8:27 AM, "XaviConde" <ja...@gruposame.com> wrote:
>
>>Hi Clint,
>>
>>Flash Profiler has a functionality to force garbage collection. I press
>>the
>>button several times and there's no instance being freed. Besides, taking
>>a
>>memory snapshot also forces garbage collection.
>>
>>On the other hand, after several hours of Flash Profiling, I have found a
>>workaround by removing the property layoutObject:
>>
>>			private function removedFromStage(event:Event):void {
>>				/* For good measure, the eventListener is removed when no longer
>>needed
>>*/
>>				parentApplication.removeEventListener(MouseEvent.CLICK,
>>mouseClickEvent);
>>				
>>//Stops memory leak
>>				this["layoutObject"]=null;
>>			}
>>
>>By removing this property (which held a CanvasLayout object added
>>dynamically) now the memory usage is stable and Profiler never reports
>>more
>>than 1 instance of NonLeakySubcomponent ever in memory.
>>
>>For what I've learned from this example, calling initialize on the child
>>object being added creates several objects which reference the child
>>object
>>itself. But when removeChild() is called, some of these circular
>>references
>>still exist. By forcing the removal as I've done it seems the circular
>>reference is broken.
>>
>>I think it should be considered a bug, since removeChild() is not undoing
>>all the actions of addChild(). I'm not sure if by letting it run enough
>>time
>>GC would remove the leaked instances; forcing the garbage collection from
>>Flash Profiler has not removed them, or the related objects. This is
>>happening on the latest 4.6.15 SDK.
>>
>>
>>
>>--
>>View this message in context:
>>http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-b
>>y
>>-addChild-tp51677p51715.html
>>Sent from the Apache Flex Development mailing list archive at Nabble.com.
>


Re: Memory leak caused by addChild() ?

Posted by Alex Harui <ah...@adobe.com>.
I took a quick look at the test case (I haven't even tried it in the
profiler yet).

I assume the test case to run is LeakByReference.mxml.  In the run()
method, it keeps storing references to the new NonLeakySubComponent on
every pass, so sure, if you don't splice out the references to the old
ones, the references array is going to cause a memory leak.

Are you saying if you are seeing a memory leak if you don't use the
references array?

-Alex

On 2/24/16, 8:27 AM, "XaviConde" <ja...@gruposame.com> wrote:

>Hi Clint,
>
>Flash Profiler has a functionality to force garbage collection. I press
>the
>button several times and there's no instance being freed. Besides, taking
>a
>memory snapshot also forces garbage collection.
>
>On the other hand, after several hours of Flash Profiling, I have found a
>workaround by removing the property layoutObject:
>
>			private function removedFromStage(event:Event):void {
>				/* For good measure, the eventListener is removed when no longer
>needed
>*/
>				parentApplication.removeEventListener(MouseEvent.CLICK,
>mouseClickEvent);
>				
>//Stops memory leak
>				this["layoutObject"]=null;
>			}
>
>By removing this property (which held a CanvasLayout object added
>dynamically) now the memory usage is stable and Profiler never reports
>more
>than 1 instance of NonLeakySubcomponent ever in memory.
>
>For what I've learned from this example, calling initialize on the child
>object being added creates several objects which reference the child
>object
>itself. But when removeChild() is called, some of these circular
>references
>still exist. By forcing the removal as I've done it seems the circular
>reference is broken.
>
>I think it should be considered a bug, since removeChild() is not undoing
>all the actions of addChild(). I'm not sure if by letting it run enough
>time
>GC would remove the leaked instances; forcing the garbage collection from
>Flash Profiler has not removed them, or the related objects. This is
>happening on the latest 4.6.15 SDK.
>
>
>
>--
>View this message in context:
>http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by
>-addChild-tp51677p51715.html
>Sent from the Apache Flex Development mailing list archive at Nabble.com.


Re: Memory leak caused by addChild() ?

Posted by XaviConde <ja...@gruposame.com>.
Hi Clint,

Flash Profiler has a functionality to force garbage collection. I press the
button several times and there's no instance being freed. Besides, taking a
memory snapshot also forces garbage collection.

On the other hand, after several hours of Flash Profiling, I have found a
workaround by removing the property layoutObject:

			private function removedFromStage(event:Event):void {
				/* For good measure, the eventListener is removed when no longer needed
*/
				parentApplication.removeEventListener(MouseEvent.CLICK,
mouseClickEvent);
				
//Stops memory leak
				this["layoutObject"]=null;
			}

By removing this property (which held a CanvasLayout object added
dynamically) now the memory usage is stable and Profiler never reports more
than 1 instance of NonLeakySubcomponent ever in memory. 

For what I've learned from this example, calling initialize on the child
object being added creates several objects which reference the child object
itself. But when removeChild() is called, some of these circular references
still exist. By forcing the removal as I've done it seems the circular
reference is broken.

I think it should be considered a bug, since removeChild() is not undoing
all the actions of addChild(). I'm not sure if by letting it run enough time
GC would remove the leaked instances; forcing the garbage collection from
Flash Profiler has not removed them, or the related objects. This is
happening on the latest 4.6.15 SDK.



--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677p51715.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: Memory leak caused by addChild() ?

Posted by Clint M <cm...@gmail.com>.
Well... it's not technically leaking... it just appears like it is because
the timer is firing every 10 ms which doesn't let garbage collection run as
fast as you think it should.

It will eventually run... you just have to wait a really long time. (Most
likely when your physical ram is full.)

In flash player garbage collection is a black box and although there are
some weird hacks you can implement to force it to run it's best just to let
it do it's thing.

Ideally you'd just slow down this timer down to give back a few frames to
let garbage collection run.

Here's an article that gives you an idea of what the player is doing.
http://www.craftymind.com/updated-elastic-racetrack-for-flash-9-and-avm2/

The gist is you need to yield code execution to the next frame. (i.e. wait
for next Event.ENTER_FRAME).

The concept is called green threading.

Try playing with framerate (max 60 because of the refresh rate of your
monitor) and the timer duration to see the garbage collection run more
often.

This is also a lesson in using the "new" keyword.  If you reuse existing
instances instead of making new ones, Flash Player doesn't need the extra
frames to run gc.

On Wed, Feb 24, 2016 at 12:20 AM, XaviConde <ja...@gruposame.com>
wrote:

> Thanks Clint, but I've commented it as well and the memory leak is still
> happening. Profiler still reports memory constantly increasing. I've also
> commented the other addEventListener calls just in case, and the only way
> to
> stop the leak is by commenting on addEventListener(). Did the Flash
> Profiler
> memory graph stop increasing in your test?
>
> Thanks in advance!
>
>
>
>
> --
> View this message in context:
> http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677p51700.html
> Sent from the Apache Flex Development mailing list archive at Nabble.com.
>

Re: Memory leak caused by addChild() ?

Posted by XaviConde <ja...@gruposame.com>.
Thanks Clint, but I've commented it as well and the memory leak is still
happening. Profiler still reports memory constantly increasing. I've also
commented the other addEventListener calls just in case, and the only way to
stop the leak is by commenting on addEventListener(). Did the Flash Profiler
memory graph stop increasing in your test? 

Thanks in advance!




--
View this message in context: http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677p51700.html
Sent from the Apache Flex Development mailing list archive at Nabble.com.

Re: Memory leak caused by addChild() ?

Posted by Clint M <cm...@gmail.com>.
Because this comment/code in NonLeakySubComponent.mxml is false and isn't a
weak ref.

/* This is not a memory leak, because BindingUtils uses weak references */

BindingUtils.bindSetter(dataProviderChanged,this,"dataProvider");

This would work:

BindingUtils.bindSetter(dataProviderChanged,this,"dataProvider", false, true);
//true is useWeakReference

On Tue, Feb 23, 2016 at 8:46 AM, XaviConde <ja...@gruposame.com>
wrote:

> Hi everyone,
>
> I'm investigating memory leaks in an application, and since the codebase is
> very complex, I've downloaded a simple project from
> http://dreamingwell.com/articles/archives/2008/05/understanding-m.php to
> understand what causes a memory leak and what doesn't. The Flash Builder
> project can be found here:
> http://dreamingwell.com/examples/flex/memoryleak/MemoryLeakTest.zip.
>
> In short, despite I follow the instructions about how to 'fix' the sample
> memory leak, the application still increases its memory usage.
>
> These are the steps I follow:
>
> 1. Donwload
> http://dreamingwell.com/examples/flex/memoryleak/MemoryLeakTest.zip.
> 2. Import into Flash Builder as a new project. It asks to update from Flex
> Builder 3. I choose to use SDK 4.6.0.
> 3. Run Flash Profiler. Live Objects view shows the counts for
> NonLeakySubComponent class increasing, and memory graph increases
> constantly
> as well.
> 4. Uncomment `references.splice( references.indexOf(lastInstance),1);' from
> LeakByReference.mxml:run(). This should fix the memory leak according to
> the
> comments.
> 5. Run Flash Profiler. Live Objects view still shows the counts for
> NonLeakySubComponent class increasing, and memory graph increases
> constantly
> as well.
> 6. Comment this.addChild(subComponent) from LeakByReference.mxml:run().
> Notice that there's a this.removeChild(subComponent) at the beginning of
> the
> function.
> 7. Run Profiler. This time, only one instance of NonLeakySubcomponent is
> displayed, and memory never increases.
>
> I would like to understand why this.removeChild() is not freeing the
> NonLeakySubComponent object, as it should (or why addChild() is creating a
> strong reference to it which causes the GC not to free it after calling
> removeChild()).
>
> Thanks in advance.
>
>
>
>
> --
> View this message in context:
> http://apache-flex-development.2333347.n4.nabble.com/Memory-leak-caused-by-addChild-tp51677.html
> Sent from the Apache Flex Development mailing list archive at Nabble.com.
>