Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
Memory best practices
Is there any guide to memory "best practices" when using Vaadin? Something that would list common gotchas or concerns. Like if you have code that adds a listener in X, you should remove it in Y. If you create a new Panel, be sure it's destroyed by calling X before you swap in another Panel. If you load a Table with beans, you should call Y to ensure the table and the references to the beans are released, etc.
I'm hopeful that the experience out there has taught some good lessons on what to avoid and what to do.
I can start with something general pointers:
- Remember that all class variables (usually) end up in the server-side session. UI state (i.e. components itself) in general does not consume significantly memory, but if storing a lot of data like this might bloat your session. Local variables are more safe in this respect.
- If caching large data sets, remember to deference them whenever they are not needed anymore.
- A good point of deferencing data is when hiding / removing a Component from a view (i.e. another component, using methods like removeComponent, detach, etc) and it is not expected to be shown again any time soon.
- Don't initialize all UI / data in Application.init function. It is typically too eager to load everything there. Instead use lazy loading of data and defer that to the activation of the view where it is needed.
Once you remember these principles, I think that is reasonable not to think too much of the memory consumption. Even some of the things here can be considered as an optimization and they can implemented quite easily later on when tuning and profiling the application.
Thanks. My concern, following the Tutorial examples, is that I create Tables and load them with beans for list/configuring one type of object in my system, then the user clicks to list/configure another, and I just call replaceComponent(currentView, newView) on my MainWindow (the app's main window that implements Window).
And the main window itself contains the navigation tree, so when the user clicks on those items to do different things, it's calling setSecondComponent(c) to change the right side SplitPanel.
Do I need to call anything to destroy the previous component? If I destroy it, I presume it will release the memory, but then I'd have to recreate it if the user clicks on the Tree item again. Is that preferable, or just change the references and keep the original component around (lazy created as you say -- but not ever destroyed).
It seems that when my view is a Table+Form on a SplitPanel, if I don't destroy it, the table will hold all those bean references. But if I do destroy it, then each time they come to that page, all of the data is re-fetched.
So for a scalable app, am I better to destroy and rebuild? Will that create its own memory leaks in the browser or Vaadin? Certainly, that was the case in the JSP/servlet world where each page refresh essentially retrieved the data from the database (we didn't cache the result set then). But now that we're in this single page world, not sure what most are doing to be both responsive to the user, but also not memory intensive for each user session.
If you wish to release memory the easiest way is to remove the component and to make sure you don't have any pointers (in fields) point to that component and related data. Just set fields to null to "destroy" it (i.e. let the Java GC to take care of freeing the memory). Of course using this pattern you need to recreate the component before next time showing it, but I don't think that is slow or anything (not the whole view is regenerated and Components like any Java objects are quite cheap). It is the data and db operations will set magnitude for server-side processing (as it is in the JSP world).
In general, with Vaadin you just kind of reverse the default what is stored to the session and what is not. And that is a good thing. So, if you know that you'll have a lot of data you should free when not shown and reload it when shown again (the JSP strategy). Mostly, it is better just to take that memory and to leave (i.e. cache) the data in the components/fields.
Thanks. I guess that makes sense. So for my smaller datasets that I use frequently and have cached in the server anyway (like our Groups and Permissions), I can just leave them alone, but our Transaction data that is subject to change all the time anyway, I can release and reload.
Does this also mean that anonymous classes that create listeners and such, if I null out the pointer to top level container (panel, window, etc.), listeners on contained buttons and such will all be release without my having to de-register them?
David Wall: Does this also mean that anonymous classes that create listeners and such, if I null out the pointer to top level container (panel, window, etc.), listeners on contained buttons and such will all be release without my having to de-register them?
Along with static fields, anonymous classes are - in any application - an easy way to create potential memory leaks. Each instance automatically holds a reference to its containing instance, which can hold references to many other instances etc. In the earlier days of Swing, this was made worse by the multiple bugs in Swing that held references to certain menus, listeners etc.
In the case of Vaadin, the component cannot know when you set a reference to it null, so no fully automatic releasing of references can occur. However, when you release all references to the objects being listened to, the garbage collector can find the whole block of objects has no outside references to it and so the listener, too, can be freed.
These are mostly common sense rules, perhaps best illustrated with an example of two alternatives for implementing a case with a tree on the left and a changing panel on the right.
- The right-hand panel has added a listener on the tree that listens to value changes and modifies the contents of the right-hand panel (through a back reference, either explicit or implicit in an anonymous class). Setting other references to the right hand panel to be null does not remove the listener, and therefore the panel cannot be released. The listener has to be explicitly removed.
- The tree has added a listener on itself that replaces the whole right hand side panel. Removing the right-hand panel from the layout and setting your references to it null will result in it being freed.
Where the system might hold references to some listeners is in the case of direct listeners for some client side events, such as layout click listeners - I cannot recall if this is the case.
Note, though, that all this is still within a session. When the application is closed for a user, all the related memory is freed. Therefore, for if the users' sessions with the application are not long, this is often not a major concern. For any large applications, some memory profiling is nevertheless recommended.