开发者

Memory usage of a GWT application

I'm currently working on a GWT application as a proof of technology for future projects. I like the way of building my AJAX code in Java instead of JavaScript. But I seem to be running into a memory problem when I repeat calls to an RPC service. The browser memory usage keeps growing and growing.

When searching Google I keep reading about how great GWT is and that its impossible to get memory leaks so can anyone explain why my browser (Firefox and Chromium) memory is rocketing?

Thanks in advance for helping me, Bram

The code:

...

class ExampleTable extends Composite

  private RPCService rpcService;
  private Timer tableUpdater;

  public ExampleTable(){
   ... Init timer and RPC Service
   ... Add components
   initWidget();
  }

  private void getTableDataFromRPCService() {
  this.rpcService.getData(new AsyncCallback<ArrayList<Data>>() {

      @Override
      public void onSuccess(ArrayList<Data> result) {
          ExampleTable.this.updateTable(result);
      }

      @Override
      public void onFailure(Throwable caught) {
          //Do nothing
      }
  });
  }

  private void updateTable(ArrayList<Data> tableData){
    ... Update the table
  }

  private void startUpdateTask() {
      this.serviceUpdater = new Timer() {
          @Override
          public void run() {
            ExampleTable.this.getTableDataFromRPCService();
          }
      };
      serviceUpdater.scheduleRepeating(2000);
  }
}

EDIT:

I've spent some time to write a test application which can be downloaded here. I ran the application for about half an hour with the table update enabled after that Firefox took about 350MB of memory. I also ran the test with the update table disabled for an hour memory usage in Firefox went to little over 100MB.

(To run this sample you need the Google visualization API for GWT which can be downloaded from Google but I'm not allowed to post the link because of a new user policy )

I just got home from work and start another test without the table data update to see if memory usage keeps increasing or if it stops at a certain point.

This is the client implementation class (GWTMemoryIssue.java):

public class GWTMemoryIssue implements EntryPoint {
//Run with or without table
private static final boolean WITH_TABLE = false; 

private final TestServiceAsync rpcService = GWT.create(TestService.class);

private Panel panel;
private Timer timer;
private Table table;

public void onModuleLoad() {
    RootPanel rootPanel = RootPanel.get();

    this.panel = new VerticalPanel();
    this.panel.setSize("100%", "100%");

    rootPanel.add(panel);

    if (WITH_TABLE) {
        loadTable();
    }else{
        startUpdateTask();
    }

}

private void startUpdateTask() {
    this.timer = new Timer() {

        @Override
        public void run() {
            GWTMemoryIssue.this.getTableData();

        }
    };
    this.timer.scheduleRepeating(2000);
}

public void loadTable() {
    Runnable onLoadCallback = new Runnable() {
        public void run() {
            GWTMemoryIssue.this.table = new Table(createTableData(), createTableOptions());
            GWTMemoryIssue.this.table.setSize("100%", "100%");
            GWTMemoryIssue.this.panel.add(GWTMemoryIssue.this.table);
            GWTMemoryIssue.this.startUpdateTask();
        }
    };

    VisualizationUtils.loadVisualizationApi(onLoadCallback, Table.PACKAGE);
}

private Options createTableOptions() {
    Options options = Options.create();

    return options;
}

private DataTable createTableData() {
    DataTable data = DataTable.create();

    data.addColumn(ColumnType.STRING, "Name");
    data.addColumn(ColumnType.NUMBER, "Intval 1");
    data.addColumn(ColumnType.NUMBER, "Intval 2");
    data.addColumn(ColumnType.NUMBER, "Intval 3");

    return data;
}

private void getTableData() {
    rpcService.getListOfItems(new AsyncCallback<ArrayList<ListItem>>(){
        public void onFailure(Throwable caught) {
            // Do nothing
        }

        public void onSuccess(ArrayList<ListItem> result) {
            if (WITH_TABLE){
                GWTMemoryIssue.this.updateTableData(result);
            }else{
                //Ignore the data from the server
            }
        }
    });
}

private void updateTableData(ArrayList<ListItem> result) {
    DataTable data = createTableData();

    data.addRows(result.size());

    int row = 0;
    for (ListItem li : result) {
        data.setValue(row, 0, li.getName());
        data.setValue(row, 1, li.getIntVal());
        data.setValue(row, 2, li.getIntSecondVal());
        data.setValue(row, 3开发者_Go百科, li.getThirdIntVal());
        row++;
    }

    this.table.draw(data, createTableOptions());
}
}


With all the additional information you provided here are some thoughts. I guess the memory increase is caused by the lists remaining in memory. It's either possible the memory is not freed at all or the JavaScript garbage collector doesn't get time to clean up, due too the short time frame between updates. Here are some test you could do:

  1. To test if the garbage collector doesn't get time adapt you code such that the update only runs a finite number of times, and then check if the memory usage decreases over a few minutes. If the memory usage decreases, than it might be less of an issue in you real world example. But simple test it by setting the delay to the 30 seconds.
  2. You could help the garbage collector by clearing the list after they are used: I don't know what works best, so here are some suggestions: Remove object from the list, or loop over the list and set values to null. This should not be necessary in normal case, because the garbage collector would do it.

You can also try the following Firefox Memory profiler add-on to see if you can locate the memory increases: http://ajaxian.com/archives/enhanced-firefox-memory-profiler-add-on


I've been using GWT quite some time with many tables and RPCs and until now most memory leaks I found were my own fault.

The RPC layer does not seem to leak as far as I know and your example is just too simple to pose a problem.

You might need to take a look at what the updateTable method is actually doing, you might have a leak in your own code.

One thing that can cause huge memory leaks with GWT are Imagebundles in IE. It is a known fact that these leak extremely in GWT because they are using DXTransform to support alpha transparency. The memory goes up in large chunks everytime widgets are put on the screen. But there are tricks to avoid this.


No there is no explicit operation needed to clean garbage in Javascript. It is supposed to run automatically (although the GC in the browser is not on the same level as in a modern JVM).

GWT does it best to avoid common pitfalls that would cause memory leaks in JS (circular references between JS and DOM nodes are badly handled in some browsers).

So the question is: is the memory usage always going up ? Or does it top out at a certain point (or it just crashes with some out of memory ?). It can be normal that your application seems to be growing and growing... but GC should kick in at some point.

In my application memory usage tops out at about 64MB. But I am not working on Ubuntu, IE on windows is our main target, although I sometimes test on FireFox as wel (and there I don't see a leak either).

One other thing you might need to do is to avoid polling every 2 seconds like you do. If a request takes longer than 2 secs you start queing up the requests (a browser has a limitation on the number of concurrent connections). so it's best to wait for the response before firing a new timer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜