2016-11-10 7 views
-2

ログファイルの行を表示するためにJTableを使用するアプリケーションを作成しています。データを解析しましたが、AbstractTableModelに行を追加しようとすると、「gcオーバーヘッドの上限を超えました」または「java.lang.OutOfMemoryError:Javaのヒープスペース」エラーが発生します。ガベージコレクタを設定するか、AbstractTableModelを変更して必要な行をロードできるようにしますか?JTableを200万行でロードする方法

package gui; 

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Date; 
import java.util.List; 
import javax.swing.table.AbstractTableModel; 
import saxxmlparse.logEvent; 

/** 
* 
* @author David.Crosser 
*/ 
public class MyTableModel extends AbstractTableModel { 

    private String[] columnNames = new String[]{"Type", "Time", "TID", "LID", "User", "Message", "Query", "Protocol", "Port", "IP", "Error"}; 
    private List<logEvent> data; 

    public MyTableModel() { 
     data = new ArrayList<>(25); 
    } 

    @Override 
    public Class<?> getColumnClass(int columnIndex) { 
     if (columnIndex == 1) { 
      //return Date.class; 
         return String.class; 

     } else { 
      return String.class; 
     } 
    } 

    @Override 
    public String getColumnName(int col) { 
     return columnNames[col]; 
    } 

    @Override 
    public int getColumnCount() { 
     return columnNames.length; 
    } 

    @Override 
    public int getRowCount() { 
     return data.size(); 
    } 

    @Override 
    public Object getValueAt(int row, int col) { 
     logEvent value = data.get(row); 
     Object retObj=null; 
     switch (col) { 
      case 0: 
       retObj = value.getType(); 
       break; 
      case 1: 
       retObj = value.getTime(); 
       break; 
      case 2: 
       retObj = value.getTid(); 
       break; 
       case 3: 
       retObj = value.getLid(); 
       break; 
       case 4: 
       retObj = value.getUser(); 
       break; 
       case 5: 
       retObj = value.getMsg(); 
       break; 
       case 6: 
       retObj = value.getQuery(); 
       break; 
        case 7: 
       retObj = value.getProtocol(); 
       break; 
       case 8: 
       retObj = value.getPort(); 
       break; 
       case 9: 
       retObj = value.getIp(); 
       break; 
       case 10: 
       retObj = "N"; 
       break; 
     } 
     return retObj; 
    } 

    public void addRow(logEvent value) { 
     int rowCount = getRowCount(); 
     data.add(value); 
     fireTableRowsInserted(rowCount, rowCount); 
    } 

    public void addRows(logEvent... value) { 
     addRows(Arrays.asList(value)); 
    } 

    public void addRows(List<logEvent> rows) { 
     int rowCount = getRowCount(); 
     data.addAll(rows); 
     fireTableRowsInserted(rowCount, getRowCount() - 1); 
    } 
} 

    package gui; 

import java.sql.ResultSet; 
import java.util.List; 
import javax.swing.SwingWorker; 
import saxxmlparse.logEvent; 

/** 
* 
* @author David.Crosser 
*/ 
public class TableSwingWorker extends SwingWorker<MyTableModel, logEvent> { 

    private final MyTableModel tableModel; 
    String query; 
    dataBase.Database db; 
    int totalRows=0; 

    public TableSwingWorker(dataBase.Database db, MyTableModel tableModel, String query) { 

     this.tableModel = tableModel; 
     this.query = query; 
     this.db = db; 
    } 

    @Override 
    protected MyTableModel doInBackground() throws Exception { 

     // This is a deliberate pause to allow the UI time to render 
     Thread.sleep(2000); 

     ResultSet rs = db.queryTable(query); 

     System.out.println("Start polulating"); 

     while (rs.next()) { 

      logEvent data = new logEvent(); 

      for (int i = 0; i <= tableModel.getColumnCount(); i++) { 
       switch (i) { 
        case 0: 
         data.setType((String)rs.getObject(i+1)); 
         break; 
        case 1: 
         data.setTime((String)rs.getObject(i+1)); 
         break; 
        case 2: 
         data.setTid((String)rs.getObject(i+1)); 
         break; 
        case 3: 
         data.setLid((String)rs.getObject(i+1)); 
         break; 
        case 4: 
         data.setUser((String)rs.getObject(i+1)); 
         break; 
        case 5: 
         data.setMsg((String)rs.getObject(i+1)); 
         break; 
        case 6: 
         data.setQuery((String)rs.getObject(i+1)); 
         break; 
        case 7: 
         data.setProtocol((String)rs.getObject(i+1)); 
         break; 
        case 8: 
         data.setPort((String)rs.getObject(i+1)); 
         break; 
        case 9: 
         data.setIp((String)rs.getObject(i+1)); 
         break; 
        case 10: 
         data.setError((String)rs.getObject(i+1)); 
         break; 
       } 
      } 
      publish(data); 

      Thread.yield(); 
     } 
     return tableModel; 
    } 

    @Override 
    protected void process(List<logEvent> chunks) { 
     totalRows += chunks.size(); 
     System.out.println("Adding " + chunks.size() + " rows --- Total rows:" + totalRows); 
     tableModel.addRows(chunks); 
    } 
} 
+1

一度に表示する項目をいくつか読み込みます。または、より多くのメモリにアクセスできるようにJVMを設定します。 http://stackoverflow.com/questions/6452765/how-to-increase-heap-size-of-jvm – bradimus

+0

なぜ以前のコメントが削除されましたか? 「+1の感謝」のようなコメントは、コメントのメリット(メタのQでなければならない)に関するメタ・ディスカッションのように、話題にはなりませんが、それは私がしたことではありませんでした。私はこれが共通の問題であることに有益な注意を払った。したがって、このコメントは、手元の問題の種類とコンピュータサイエンスにおけるその場所に関するコメントでした。このことを誤解した人は、このようなコメントから利益を得ることができます。 2人がそれから恩恵を受けた可能性があります。私は適切なものについてはSOのページを読んだ。あなたが削除するのに十分なコンテンツに同意しない場合は、推論で私たちに啓発する必要があります。 – Aaron

+1

この関連[例](http://stackoverflow.com/a/25526869/230513)も参照してください。 – trashgod

答えて

2

私の答えはあなたが非常に大規模なデータセットで作業する必要がある問題の一般的なタイプ、問題だけではなく、特定の「テーブル2万行」に適用されます。

操作する必要があるデータが一部のコンテナよりも大きい場合(実際にはシステムよりも多くのメモリがありますが、これはコンテナより大きなデータ論理的な方法など)、ある時点で必要なデータだけをストリーミングするためのメカニズムを作成する必要があります。

たとえば、表に10行を表示でき、データセットが大きすぎる場合は、現在表示されている10行分のテーブルモデルを作成する必要があります。ビューを変更したときに必要なデータとそのデータを交換します。だから、200万ではなく10のレコードを保持するテーブルモデルを作成します。または、私が言及したオプションのバッファリングについては、モデルに30レコードを保持させてください。ビュー内の10個のレコード、前後の10個のデータが含まれているため、小さなスクロールバーのインクリメントが非常に反応するようにユーザーがテーブルをスクロールするとすぐにデータを変更できます。ユーザーは非常に速くスクロールします(つまり、スクロールバー「親指」をクリックし、すぐ上から下にドラッグします)。

これは、圧縮アルゴリズムが100GBのデータを圧縮/解凍するのと同じ方法です。一度にすべてのことが記憶に残るわけではありません。または、テープドライブによってバックアップされたソフトウェアがどのように機能するか(ランダムアクセスではないので選択できません)。あるいは、ほぼすべての人がよく知っている例です。これがオンラインビデオストリーミングの仕組みです。動画の下部にあるYouTubeとローディングバーは、灰色のバッファゾーンであると考えてください。そのバッファーゾーンの時間に「早送り」するとすぐに切り替わることがよくありますが、それまでの時間に変更すると、ビデオが次のフレームをロードしている間に1秒間停止する可能性があります。これは、メモリやディスクからデータ・モデルに「ストリーミング」していること、ストリーム・ソースとデスティネーションが同じプロセスにあることを除いて、巨大なテーブルがどのように機能するかです。そうでなければ、同じ考え。

関連する問題