2016-11-10 40 views
-2

我正在编写一个应用程序,它使用JTable来显示日志文件的行。我解析了数据,但是当我尝试将行添加到我的AbstractTableModel时,收到“超出gc开销限制”或“java.lang.OutOfMemoryError:Java堆空间”错误。有没有配置垃圾收集器或更改我的AbstractTableModel以允许我加载所需的行?如何装载2百万行的JTable

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行,并让它在视图更改时将数据交换出来。因此,创建一个包含10条记录的表格模型,而不是200万。或者对于我提到的可选缓冲区,使模型保存30条记录;视图中的10条记录以及前后10条记录,以便您可以在用户滚动表格时立即更改数据,以便小型滚动条增量具有高度响应性 - 然后流式传输数据的问题仅在用户滚动的速度非常快(即:单击滚动条“拇指”并将其从上到下立即拖动)。

这与压缩算法压缩/解压缩100GB数据的方式相同;这并不是所有的记忆。或者磁带驱动器支持的软件是如何工作的(他们没有选择,因为它不是随机访问的)。或者,几乎每个人都熟悉的例子:这就是在线视频流的工作原理。考虑YouTube和视频底部的加载栏及其灰色缓冲区;如果您“快进”到该缓冲区中的某个时间,它通常会立即切换,但如果您更改为过去的时间,视频可能会在加载下一帧时停止一秒(然后缓冲更多)。这是一个巨大的表格,除了你从存储器或磁盘“流”到数据模型之外,流源和目的地都在同一个进程中。否则,相同的想法。