Memory Leak IE7 & GWT 2.0.4

105 views
Skip to first unread message

chrisr

unread,
Aug 26, 2010, 11:19:33 AM8/26/10
to Google Web Toolkit, chris....@sungard.com
I created a simple application in an attempt to reproduce a memory
leak issue in our decently large GWT application.

This test application basically contains a split panel with a button
on the left, and a tab panel full of large blocks of text on the
right.
Clicking the reload button fires the reloadRight method, and does a
panel.clear() to remove the old tab panel and a panel.add() to add a
new tab panel to the right panel. Doing this repeatedly causes memory
consumption to increase without bounds.

For example, on the initial load IE7 uses around 35 MB. 125 clicks
later its using nearly 1.5GB.

Is this example doing something in a fundamentally incorrect way?
How can I keep memory usage from exploding like this?


/* Example Below */


package com.example.myproject.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DecoratedTabPanel;
import com.google.gwt.user.client.ui.DecoratorPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HorizontalSplitPanel;
import com.google.gwt.user.client.ui.RootPanel;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class TestApplication01 implements EntryPoint {

/**
* This is the entry point method.
*/
public void onModuleLoad() {
RootPanel.get("container").add( new MainPanel() );
}

private class MainPanel extends DecoratorPanel{

private HorizontalSplitPanel hsp;
private HTMLPanel lPanel;
private HTMLPanel rPanel;
private DecoratedTabPanel tabPanel;
int rightPanelCount = 0;

public MainPanel(){
hsp = new HorizontalSplitPanel();
hsp.setSplitPosition("25%");
hsp.setSize("800px", "400px");
lPanel = new HTMLPanel("<div id=\"reloadButton
\"/>");

rPanel = new HTMLPanel("<div id=\"right-panel-
contents\"/>");
Button reloadButton = new ReloadButton(this);
reloadButton.setVisible(true);
lPanel.add( reloadButton, "reloadButton" );
hsp.setLeftWidget(lPanel);
hsp.setRightWidget(rPanel);
this.add( hsp );
reloadRight();
}

char[] chars = new char[] {' ',' ',' ', ' ', ' ',
'a','b','c','d','e','f','g','h','i','j','k','l','m',

'n','o','p','q','r','s','t','u','v','w','x','y','z' };

private String getSomeText(int length){
StringBuffer sb = new StringBuffer(length);
for ( int i=0; i<length; ++i ){

sb.append( chars[ (int)Math.round(Math.random()*(chars.length-1)) ]);
if ( i>0 && i % 60 == 0 )
sb.append("<br>");
}
return sb.toString();
}


protected void reloadRight(){
++rightPanelCount;
rPanel.clear();

tabPanel = new DecoratedTabPanel();
tabPanel.setWidth("400px");
tabPanel.setAnimationEnabled(true);

String text = "Load count = "+rightPanelCount;

tabPanel.add( new HTML(text
+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab One");
tabPanel.add( new HTML(text
+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Two");
tabPanel.add( new HTML(text
+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Three");
tabPanel.add( new HTML(text
+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Four");
tabPanel.add( new HTML(text
+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Five");
tabPanel.selectTab(0);

rPanel.add( tabPanel, "right-panel-contents" );
}

private class ReloadButton extends Button{

private MainPanel mainPanel;

public ReloadButton(MainPanel p){
super("Reload Right Panel");
this.mainPanel = p;

this.addClickHandler(getClickHandler());
}

private ClickHandler getClickHandler(){
return new ClickHandler(){

@Override
public void onClick(ClickEvent
event) {

mainPanel.reloadRight();
}
};
}
}
}

}

chrisr

unread,
Aug 25, 2010, 3:56:31 PM8/25/10
to Google Web Toolkit
rPanel = new HTMLPanel("<div id=\"right-panel-contents\"/>");
Button reloadButton = new ReloadButton(this);
reloadButton.setVisible(true);
lPanel.add( reloadButton, "reloadButton" );
hsp.setLeftWidget(lPanel);
hsp.setRightWidget(rPanel);
this.add( hsp );
reloadRight();
}

char[] chars = new char[] {' ',' ',' ', ' ', ' ',
'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z' };

private String getSomeText(int length){
StringBuffer sb = new StringBuffer(length);
for ( int i=0; i<length; ++i ){

sb.append( chars[ (int)Math.round(Math.random()*(chars.length-1)) ]);
if ( i>0 && i % 60 == 0 )
sb.append("<br>");
}
return sb.toString();
}


protected void reloadRight(){
++rightPanelCount;
rPanel.clear();

tabPanel = new DecoratedTabPanel();
tabPanel.setWidth("400px");
tabPanel.setAnimationEnabled(true);

String text = "Load count = "+rightPanelCount;

tabPanel.add( new HTML(text+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab One");
tabPanel.add( new HTML(text+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Two");
tabPanel.add( new HTML(text+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Three");
tabPanel.add( new HTML(text+"<br>"+getSomeText((int)
(Math.random()*500)+500000)), "Tab Four");
tabPanel.add( new HTML(text+"<br>"+getSomeText((int)

chrisr

unread,
Aug 27, 2010, 8:20:43 AM8/27/10
to Google Web Toolkit
Sorry for posting this twice. If a moderator wants to/can remove the
duplicate go ahead.

Joel Webber

unread,
Aug 27, 2010, 1:52:53 PM8/27/10
to Google Web Toolkit
Hmm... I've tried to reproduce this on IE7 and IE8 (both quirks &
standards), to no avail. I doubt it's anything in the outer HTML file,
but just in case, here's what I used:

<!DOCTYPE HTML>
<html>
<head>
<title>Hello</title>
<script type="text/javascript" language="javascript" src="hello/
hello.nocache.js"></script>
</head>
<body>
<div id='container'></div>
</body>
</html>

The initial calls to getSomeText() were causing a huge number of slow-
script warnings on IE, so I was only able to run through a few
iterations. I then dropped the count by a factor of 10 to get the SSWs
under control, and the memory usage appears quite stable after a
couple of hundred clicks. (~30MB). Can you think of anything else that
might be different in your setup?

chrisr

unread,
Aug 27, 2010, 4:21:33 PM8/27/10
to Google Web Toolkit
Hi Joel, i appreciate your help.

I was running in development mode and it appears that this memory
bloat goes away when not using development mode.
We have been developing our application using older GWT (1.5.4 I
belive) so I'm used to using the old hosted mode. I didn't realize
the in browser development mode might have this side effect.

The goal of this was to reproduce a memory leak that we have in our
application (when compiled, of course) using as simple a case as
possible, in the newest version of GWT, if possible. I erroneously
thought this was accomplishing that.

Does the fact that this growth occurs in development mode suggest
anything about why I might see similar growth in a compiled GWT 1.5.4
application?

Michael W

unread,
Aug 28, 2010, 12:48:44 PM8/28/10
to Google Web Toolkit
I doubt following code causing the memory leak.
In reloadRight method, you create and assign new DecoratedTabPanel()
to tabPanel every time.

protected void reloadRight(){
++rightPanelCount;
rPanel.clear();

tabPanel = new DecoratedTabPanel();

You may reuse existing tabPanel instead of create new one.

Marcos Paulo

unread,
Aug 27, 2010, 10:49:50 AM8/27/10
to google-we...@googlegroups.com
Guys please help,

I'm passing throuth the same problem, the moderator from smargwt forum told me to
call destroy() in components that i don't need anymore, but my architecture uses MVP,
and i have only one container which changes the content to render diferent pages...
when I call destroy() in him and then I put the new component, he doesn't render anymore.

I have an aplication getting into production and I am passing throuth memory leak crashes on
browser... If someone can help me, pliz help.

I'm desperate,
--
Marcos Paulo Damasceno
Desenvolvedor Java
(85) 8140-0111
Twitter: www.twitter.com/_marcospaulo_
Del.ici.ous:
www.delicious.com/marcospaulo_
MSN: 
marcospaul...@hotmail.com

------------------------------------------------------------------------------------------------------------------------
"Grandes resultados requerem grandes ambições."
(Heráclito)

“Se suas ações inspiram outros a sonhar mais, aprender mais, fazer mais, tornar-se mais, você é um líder.”
(John Quincy Adam)

"Se tudo fosse perfeito, amanhã não poderia ser melhor"



2010/8/27 chrisr <chris.robe...@gmail.com>
--
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-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.


Marcos Paulo

unread,
Aug 27, 2010, 2:16:16 PM8/27/10
to google-we...@googlegroups.com
The problem is really clear, the components still exists after i change the content from mainContainer,
that in MVP it's like go to another page... How do i have sure? because give a id for a component then
i go to page twice and in the second time, an error ocurred telling me that the it could not create another
component with the same id, so the old one, even if it is not showing, still exist there....

The solution?? call destroy from component.. but... it happens what i told in my last e-mail...

My memory leak happens in all browsers, IE 8, Firefox 3.6 and Safari 4...

I am using SmartGwt....

If someone could please give a hint to solve this problems, i would apriciate...
tnks

--
Marcos Paulo Damasceno
Desenvolvedor Java
(85) 8140-0111
Twitter: www.twitter.com/_marcospaulo_
Del.ici.ous:
www.delicious.com/marcospaulo_
MSN: 
marcospaul...@hotmail.com

------------------------------------------------------------------------------------------------------------------------
"Grandes resultados requerem grandes ambições."
(Heráclito)

“Se suas ações inspiram outros a sonhar mais, aprender mais, fazer mais, tornar-se mais, você é um líder.”
(John Quincy Adam)

"Se tudo fosse perfeito, amanhã não poderia ser melhor"



2010/8/27 Joel Webber <j...@google.com>

chrisr

unread,
Aug 30, 2010, 9:10:57 AM8/30/10
to Google Web Toolkit
This may be a valid solution, however its not an ideal one, as this
application is already significantly large, and its not going to be
easy to refactor all of the existing code to work this way. It will
be easy to keep this in mind while going forward, however.

As I said above, I was trying to reproduce the way a lot of the code
I'm working with has been written. Also, while I thought this was
reproducing the situation we are seeing in our live app (using GWT
1.5.4) it turns out this only produces the memory leak in development
mode using the most recent GWT. I will have to see if this produces a
leak when compiled using 1.5.4. If not then I'll probably need to
find a new simple case that reproduces the leak we're seeing.

Joel Webber

unread,
Sep 3, 2010, 8:12:18 AM9/3/10
to Google Web Toolkit, Joel Webber
Sorry I didn't follow up earlier (this should have showed up in my
inbox, but didn't for some reason...).

@chrisr:
It is at least remotely possible that this could have leaked in 1.5.4,
but I'm not aware of any memory-leak fixes as recently as that. The
architecture that guards against leaks is sound, and hasn't changed
significantly since 1.0. There were a couple of bug fixes for little
pieces of Javascript that were triggering leaks (notably in the
RequestBuilder code, which this doesn't exercise), but that was some
time ago. As for the dev mode leak, I've asked one of my team members
who's working on optimizing dev mode to take a look at that.

@Marcos:
I wish I could do more to help with memory leaks in SmartGWT, but
that's way beyond the knowledge of anyone on our team. SmartGWT's a
wrapper around a huge Javascript library that, from your earlier post,
appears to require destroy() calls on widgets as part of its memory-
leak strategy (IIUC). That strategy's rife with problems and very hard
for users to get right in practice (I've tried it in other frameworks,
and always found myself squashing leaks ad infinitum). Do the SmartGWT
tools not provide some mechanism for tracing and finding leaks?
> ...
>
> read more »

Chris Conroy

unread,
Sep 3, 2010, 11:52:29 AM9/3/10
to google-we...@googlegroups.com, Joel Webber
@chrisr:

Are you seeing a leak in the Development Mode JVM, or are you observing it in the browser?

--
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-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.




--
Chris Conroy
Software Engineer
Google, Atlanta

chrisr

unread,
Sep 3, 2010, 3:00:13 PM9/3/10
to Google Web Toolkit
The sample code I provided only produces the memory leak in hosted
mode.
I am however experiencing a memory leak in my real world app, I just
haven't written any sample code the demonstrates it in IE (the only
browser we currently build for.)
> ...
>
> read more »

Chris Conroy

unread,
Sep 3, 2010, 3:18:22 PM9/3/10
to google-we...@googlegroups.com
Okay, well if it's *in* hosted mode (read: the JVM), then it's a known issue that I'm working on at the moment.

> ...
>
> read more »

--
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-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

chrisr

unread,
Sep 7, 2010, 8:18:11 AM9/7/10
to Google Web Toolkit
Does the issue that you're working on now give you any reason to
believe it could be an issue in the browser as well, under some
similar circumstances?

On Sep 3, 2:18 pm, Chris Conroy <con...@google.com> wrote:
> Okay, well if it's *in* hosted mode (read: the JVM), then it's a known issue
> that I'm working on at the moment.
>
> On Fri, Sep 3, 2010 at 3:00 PM, chrisr <chris.robert.rowl...@gmail.com>wrote:

Chris Conroy

unread,
Sep 7, 2010, 11:51:17 AM9/7/10
to google-we...@googlegroups.com
No. This particular issue is isolated to the DevMode JVM.


--
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-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

ckendrick

unread,
Sep 7, 2010, 10:22:10 PM9/7/10
to Google Web Toolkit
Just a note on SmartGWT -

Built-in GWT widgets rely on the browser to garbage collect a detached
DOM tree. In older browsers like IE6/7 we found a number of cases
where this didn't work completely, so we opted for manual destroy().
It's possible that as of IE8/9 all such leaks are gone (personally I
find this unlikely :), but, we're not really interested in finding
out.

And yes, we have tools that make leaks obvious - the Watch Tab in the
Developer Console, which shows a tree of all components. You tend to
spot leaked components right away while using the tool for other
purposes.
> ...
>
> read more »

sandeep

unread,
Sep 8, 2010, 9:14:08 AM9/8/10
to Google Web Toolkit
Hi,

You are clearing some panel by calling "clear()" method and adding in
it again. But clear method clear the panel only not instances. Browser
has a limitation of loading instances. If it exceeds, we get memory
leak issue. One way to solve is 'reloading the page'. Track the event
of page and reload the page from that point.

ckendrick

unread,
Sep 8, 2010, 1:37:00 PM9/8/10
to Google Web Toolkit
Just one more note on this: in SmartGWT calling destroy() on a parent
automatically destroy()s all children recursively, all widgets that
generate children (eg ListGrids generate a header) automatically
destroy those children with themselves, and removed tabs automatically
destroy their panes unless you tell them not to.

The net result of this is that there's no need for a manual destroy()
call anywhere in the Showcase, or in most applications that use the
pattern of generating new tabs. Further, in any situation where
you're trying to permanently get rid of a component, where you would
otherwise call something like layout.removeMember(member) you just
call member.destroy() instead (and this takes care of layout removal
as well).

Just wanted to clarify all this since there was speculation the
strategy would be "rife with problems" and "very hard for users to get
right". It's understandable that experience with some previous
framework would make someone think so, but it's very easy in SmartGWT,
and we think an explicit destroy() is the right approach in terms of
giving us the opportunity to work around browser garbage collection
bugs.

On Sep 7, 7:22 pm, ckendrick <charles.kendr...@gmail.com> wrote:
> Just a note onSmartGWT-

Marcos Paulo

unread,
Sep 8, 2010, 11:51:23 PM9/8/10
to google-we...@googlegroups.com
@ckendrick 

Thank u for ur reply about GWT, but i am passing trough some problems
with the destroy, today, my application has a AppController that handle
all the page switching, i have one interface that all presenters implements,
in this interface i put the current page, when i want to change the page, i fire
a event that goes to this AppController and change the object(Presenter) in 
that interface then calls go passing the main container and inside the go i change
the implementation of this container to the current view that i want to show...

The problem is, if i call destroy in this container before change him so the
new page can be displayed, the page doesn't appear, like that reference container
doesn't have any value anymore, but if i debug, i see that the container has an object,
but it doesn't appear.... i don't know what can i do anymore...

i really need some help because last less then one month for
the application starts working on the net and this problems persists.

Tnks for replys,




 
--
Marcos Paulo Damasceno
Desenvolvedor Java

Twitter: www.twitter.com/_marcospaulo_
Del.ici.ous:
www.delicious.com/marcospaulo_
MSN: 
marcospaul...@hotmail.com

------------------------------------------------------------------------------------------------------------------------
"Grandes resultados requerem grandes ambições."
(Heráclito)

“Se suas ações inspiram outros a sonhar mais, aprender mais, fazer mais, tornar-se mais, você é um líder.”
(John Quincy Adam)

"Se tudo fosse perfeito, amanhã não poderia ser melhor"



2010/9/8 ckendrick <charles....@gmail.com>

chrisr

unread,
Oct 11, 2010, 12:32:19 PM10/11/10
to Google Web Toolkit
Got pulled off to work on other issues, finally coming back to this
again.

I managed to find a way to fix one of the memory "leaks" in the
application. I was under the impression that you didn't have to
explicitly remove things from the DOM in this way, so I'm curious why
it seems to solve my problem.

Basically I changed this:

public void doSomething(){
panel = null;
}

to

public void doSomething(){
if ( panel != null ) {
DOM.removeChild(RootPanel.getBodyElement(),
panel.getElement() );
panel = null;
}
}

chrisr

unread,
Oct 12, 2010, 10:58:59 AM10/12/10
to Google Web Toolkit
My mistake, this actually only "fixed" the memory leak because it was
throwing a js error that prevented the code from continuing on to leak
memory.
Reply all
Reply to author
Forward
0 new messages