Thursday, March 31, 2011

Re: MVP + Handlers + Carelessness = Memory Leak ?

First of all thank your all for your replies, especially Thomas' for
shedding some light on garbage collection, etc. :-) (I'm no full time
programmer, so I don't know many subtleties of programming...)

The point is, that I kind of have an old but "big" (relative I guess)
application (in fact I wrote it myself in my GWT starter times, with
GWT 1.7.1 knowledge ;-) and now I'm building widgets following MVP and
integrating them into the old application. Normally I just inject a
SimpleEventbus via Gin into the presenter to let the application
attach custom handlers, then I use standard GWT to get the view
interactive. Meaning I just insert Methods to do stuff like

view.getButton().addClickHandler(new ClickHandler(){ ... })

into the view, so the view has

HasClickHandlers getButton();

in the interface and returns the appropriate button.
I guess GWT is maintaining these handlers itself, disposing of them,
when necessary? So I don't have to null out those ClickHandlers at any
time? Or do I have to care? I guess if the views are singletons I
definitely have to, right? But what if all gets disposed at the same
time? Are the ClickHandlers killed?
Anyway recently I hacked something similar into it with a custom
interface / class, same as the BlubbHandler above, which has no
HandlerManager / Eventbus, and just does it directly, not taking care
of disposing anything. So I kind of have a Presenter -> View ->
BlubbHandler -> Presenter dependency and no HandlerManager. And it is
altogether thrown away, when not used anymore. I guess due to Thomas'
comment this means, that the memory is still freed, correct?
Besides that the application is of course more complex, it normally
follows the pattern load(new Page()) where a Page-Object is created,
then the page-object instantiates all it's widgets which are partially
in MVP containing other widgets partially in MVP.
So I guess often a pattern like the following appears:
A1 is disposed, the references are A1 -> ... -> An -> B -> C -> An
I take it, that still normally all those things should be garbage
collected, since there is no reference from the running application to
any of them anymore. Is this generally the case?

I always thought Places / Activities are for the bottom structure, and
not for constructing single widgets. Unfortunately I'm not independent
in creating this application and my suggestion for a refactoring to
activities / places was rejected... Therefore I can just follow
patterns and best practices I have learned in time for new parts of
the application.

Would it be a good pattern to do the following:
- Declare the View as Singleton in Gin (to spare the heavy unnecessary
DOM operations)
- Attach a DisposeHandler to the View, enabling to fire Dispose events
that will make the underlying Presenter detach itself from the view
- Override the void onUnload() method of the view to fire a
DisposeEvent
Therefore by adding a DisposeHandler to the View in the Constructor of
the Presenter would be sufficient to make sure that whenever the
widget is unloaded, the presenter's references are nulled out and the
presenter (being not singleton) is disposed

Then I could also write a base class AbstractPresenter that would
already take care of adding such a Handler and a base class
AbstractView, etc. providing an addDisposeHandler(DisposeHandler
handler) method and overriding the onUnload() method. Just so I would
never forget to null out the presenter's references...

Is there an error in this pattern? Or would it provide the following:
- One time instantiation of Views
- New Presenters for every call
- Save approach to presenter <-> view references, that nulls out view
references before the presenter is disposed
- And of course: No memory leaks ;-)

Thank you all for helping me to improve my GWT knowledge :-)


On Mar 31, 12:54 pm, Thomas Broyer <t.bro...@gmail.com> wrote:
> On Wednesday, March 30, 2011 7:58:43 PM UTC+2, pete wrote:
>
> > Hallo,
>
> > I'm not sure how GWT handles this, so I want to evaluate a short
> > example scenario for memory leaks. Suppose I write my own handler
>
> > public Interface BlubbHandler {
> >     void onBlubb(BlubbEvent event);
> > }
>
> > have my presenter
>
> > public class MyPresenter {
> >     private final MyView view;
> >     private final StringContainer justToBeFinal;
>
> >     @Inject
> >     public MyPresenter(MyView view) {
> >         this.view = view;
> >         view.addBlubbHandler(new BlubbHandler(){
> >             justToBeFinal.setText("BLUBB");
> >         });
> >     }
> > }
>
> > and now my Widget is disposed. Will the memory it uses ever be freed?
> > Or does the reference to view prevent view from being disposed,
>
> Yes.
>
> > and
> > the reference of view's BlubbHandler to justToBeFinal prevent
> > MyPresenter to be disposed?
>
> It depends how the view keeps a reference to the BlubbHandler (or rather *
> who* keeps a reference to it).
> Having A keeping a reference on B, and B a reference on A doesn't
> (necessarily) create a memory leak: both will be reclaimed when there's no
> longer any reference to any of them.
>
> > I'm not even sure, how it would be in Java, but I think in Java this
> > would cause a memory leak, wouldn't it?
> > So do I have to add a dispose() method to pesenter, that must be
> > called to null out the BlubbHandlers of view?
> > And how is this handled with GWT's own event system? Or with event
> > systems constructed on top of GWTs own one, using SimpleEventBus and
> > extending / implementing GWT's classes?
>
> As I said above, it depends *who* keeps a reference on the handlers, and its
> lifetime. If you're using a HandlerManager (or EventBus) that has the same
> lifetime as the view, then you've just changed the A->B->A above to
> A->B->C->A, but it's still OK.
>
> > Anyone who is more versatile in these matters and can help me would be
> > very appreciated :-) I don't want to find out after lines and lines of
> > code, that I'm memory leaking like stupid...
>
> Given that anything related to the DOM is quite heavyweight and slow, it
> could be a good idea to keep some views around as singletons (instead of
> building a new one each time). Presenters are on the other hand generally
> lightweight objects, so having them short-lived makes them easier to code
> (as you don't have to reset their internal state each time they're reused).
> That means it's good practice to include "dispose" methods in presenters to
> "detach" from the view, thus preventing memory leaks (if you create 10
> presenters for a single view, and never "detach" them, you'll still have all
> 10 in memory *and* listening to events *and* probably trying to update the
> shared view all at once; bad for memory usage, bad for performance, and
> highly error prone!)
> As Jambi suggested, GWT 2.1 Activities makes it easy, as an activity's
> lifecycle is clearly define: it starts (time where you "attach" to the view)
> and then either is cancelled (before it has finished
> asynchronously-starting) or is later stopped (time to "detach" from the
> view).
>
> In the end, it all depends how you manage the lifecycle and lifetime of your
> objects.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsubscribe@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

No comments:

Post a Comment