memory leaks (solved)

EDIT: apparently this isn’t a threadlocal or Appfoundation issue, it was related to session management, which it would seem it’s pretty dangerous if left unchecked

I have a ThreadLocal variable set to the class extending Application (the entry point class), say MyApplication class.

It’s initialized and used like this:


@Override
	public void transactionEnd(Application application, Object transactionData) {
...
if (application == ReallotoApplication.this) {
			ReallotoApplication.currentApplication.set(null);
			ReallotoApplication.currentApplication.remove();
		}
}
@Override
	public void transactionStart(Application application, Object transactionData) {
		if (application == ReallotoApplication.this) {
			ReallotoApplication.currentApplication.set(this);
		}
	}

The problem starts when I close the browser windows, which triggers this:

mainWindow.addListener(new Window.CloseListener() {

			@Override
			public void windowClose(CloseEvent e) {
				if (ReallotoApplication.currentApplication.get() == ReallotoApplication.this) {
					ReallotoApplication.currentApplication.set(null);
					ReallotoApplication.currentApplication.remove();
				}

				close();
			}
		});

and this:

@Override
	public void close() {
		if (ReallotoApplication.currentApplication.get() == this) {
			ReallotoApplication.currentApplication.set(null);
			ReallotoApplication.currentApplication.remove();
		}

		super.close();
	}

but watching in VisualVM, I see all the ReallotoApplication instances sticking after I closed the browser window (and close() triggered), and even if I call garbage collector from VisualVM a couple of times, they don’t go away, which means it’s a memory leak. I left for 30 mins, but they were still. I also tested if the session timeout was involved, it seemed not. Experimenting around it seems that only when I close the browser window on the application it remains stuck in memory, if I press exit which goes on to call close() it does not.

How to fix this please? I want the ReallotoApplication instances to go away after close() is triggered, or browser tab/window is closed

I’m using Tomcat 7.0.16.0 and Vaadin 6.7.3

I had this enabled in my application init()

//		((WebApplicationContext) this.getContext()).getHttpSession()
//				.setMaxInactiveInterval(86400);

Apparently there isn’t any leak if session manages to expire… :grin:

Also, all the code needed to handle browser window/tab close is this (removing the threadlocal instance makes no difference):

// INFO: this closes the application if the user refreshes the page
		mainWindow.addListener(new Window.CloseListener() {

			@Override
			public void windowClose(CloseEvent e) {
				close();
				// if you don't invalidate, a malicious user can kill your
				// server with an out of memory error, because each refresh will
				// leave an instance in memory
				((WebApplicationContext) ReallotoApplication.this.getContext())
						.getHttpSession().invalidate();
			}

		});

While having some peculiar behaviour:
I open an application instance in Firefox, then,
I open 4 application instances in IE tabs, then
I close the 4 application instances in IE tabs

What happens is only one instance disappears immediately from memory.
If I close the Firefox instance, again, only one instance disappears from memory.
It seems this only closes one instance per browser for some reason, everything else that was opened in that browser, separate windows and tabs remain for a while.

After the session expires the 3 instances remaining disappear too.

Note that in IE8, each tab is really a window instance, and result in an application instance being stuck in memory, though sometimes it still manages to break consistency by displaying another instance (I think), in which case I get an “Communication problem: invalid security key” error

Also note that if you don’t register a close listener like the above one, refreshing the page won’t cause instances to remain in memory if refreshing in Firefox, but if refreshing in IE8, each refresh creates an instance server side, which will remain until session timeout. In a flood this will result in an out of memory error

How are you creating the 4 different sessions in the 4 different tabs ? Can you print the sessionId (get it from your http request through a listener) on each tab to see which is which ?

By “Note that in IE8, each tab is really a window instance”, I meant each tab is an internet explorer instance, or internet explorer window, such as opening a new internet explorer window.

That’s why you get different sessions in different tabs.

If you refresh same tab in IE8 or Firefox, regardless, you get a different session ID each refresh.

Try it yourself in IE8, implement

public class ReallotoApplication extends Application implements
		ApplicationContext.TransactionListener, [b]
HttpServletRequestListener
[/b]

then add

@Override
	public void onRequestStart(HttpServletRequest request,
			HttpServletResponse response) {
		
		[b]
System.out.println(request.getSession().getId());
[/b]
		
	}

Refreshing:

IE8

Firefox

New tabs:

IE8

Firefox

3390B2B3936428F81F7353A34D3494F9
3390B2B3936428F81F7353A34D3494F9
3390B2B3936428F81F7353A34D3494F9
3390B2B3936428F81F7353A34D3494F9
3390B2B3936428F81F7353A34D3494F9
3390B2B3936428F81F7353A34D3494F9