2016-11-10 54 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和視頻底部的加載欄及其灰色緩衝區;如果您「快進」到該緩衝區中的某個時間,它通常會立即切換,但如果您更改爲過去的時間,視頻可能會在加載下一幀時停止一秒(然後緩衝更多)。這是一個巨大的表格,除了你從存儲器或磁盤「流」到數據模型之外,流源和目的地都在同一個進程中。否則,相同的想法。