私は現在、将来のプロジェクトのテクノロジーの証明としてGWTアプリケーションに取り組んでいます。JavaScriptではなくJavaでAJAXコードを作成する方法が好きです。しかし、RPCサービスへの呼び出しを繰り返すと、メモリの問題が発生しているようです。ブラウザのメモリ使用量は増え続けています。
Googleを検索するとき、GWTがどれほど優れているか、メモリリークを取得することは不可能であるということを読み続けているので、ブラウザ(FirefoxとChromium)のメモリが急増している理由を誰かが説明できますか?
助けてくれてありがとう、ブラム
コード:
...
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);
}
}
編集:
ここからダウンロードできるテストアプリケーションを作成するのに少し時間を費やしました。Firefoxが約350MBのメモリを使用した後、テーブルの更新を有効にしてアプリケーションを約30分間実行しました。また、Firefoxのメモリ使用量が100MBを少し超えるまで、更新テーブルを無効にしてテストを実行しました。
(このサンプルを実行するには、GoogleからダウンロードできるGWT用のGoogle視覚化APIが必要ですが、新しいユーザーポリシーのため、リンクを投稿することはできません)
仕事から家に帰って、テーブルデータを更新せずに別のテストを開始して、メモリ使用量が増え続けるかどうか、または特定の時点で停止するかどうかを確認しました。
これは、クライアント実装クラス(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, li.getThirdIntVal());
row++;
}
this.table.draw(data, createTableOptions());
}
}