Java 如何加载200万行的JTable

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

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

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);
    }
}
packagegui;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.Date;
导入java.util.List;
导入javax.swing.table.AbstractTableModel;
导入saxxmlparse.logEvent;
/**
*
*@作者大卫·克罗斯
*/
公共类MyTableModel扩展了AbstractTableModel{
私有字符串[]columnNames=新字符串[]{“类型”、“时间”、“TID”、“LID”、“用户”、“消息”、“查询”、“协议”、“端口”、“IP”、“错误”};
私人名单数据;
公共MyTableModel(){
数据=新阵列列表(25);
}
@凌驾
公共类getColumnClass(int columnIndex){
如果(columnIndex==1){
//返回日期.class;
返回字符串.class;
}否则{
返回字符串.class;
}
}
@凌驾
公共字符串getColumnName(int-col){
返回列名[col];
}
@凌驾
public int getColumnCount(){
返回columnNames.length;
}
@凌驾
public int getRowCount(){
返回data.size();
}
@凌驾
公共对象getValueAt(整数行,整数列){
logEvent值=data.get(行);
Object retObj=null;
开关(col){
案例0:
retObj=value.getType();
打破
案例1:
retObj=value.getTime();
打破
案例2:
retObj=value.getTid();
打破
案例3:
retObj=value.getLid();
打破
案例4:
retObj=value.getUser();
打破
案例5:
retObj=value.getMsg();
打破
案例6:
retObj=value.getQuery();
打破
案例7:
retObj=value.getProtocol();
打破
案例8:
retObj=value.getPort();
打破
案例9:
retObj=value.getIp();
打破
案例10:
retObj=“N”;
打破
}
返回retObj;
}
public void addRow(日志事件值){
int rowCount=getRowCount();
数据增值;
fireTableRowsInserted(rowCount,rowCount);
}
public void addRows(logEvent…值){
addRows(Arrays.asList(value));
}
公共void addRows(列表行){
int rowCount=getRowCount();
data.addAll(行);
fireTableRowsInserted(rowCount,getRowCount()-1);
}
}
软件包图形用户界面;
导入java.sql.ResultSet;
导入java.util.List;
导入javax.swing.SwingWorker;
导入saxxmlparse.logEvent;
/**
*
*@作者大卫·克罗斯
*/
公共类TableSwingWorker扩展了SwingWorker{
私有最终MyTableModel tableModel;
字符串查询;
数据库数据库;
int totalRows=0;
public TableSwingWorker(dataBase.dataBase db、MyTableModel tableModel、字符串查询){
this.tableModel=tableModel;
this.query=query;
这个.db=db;
}
@凌驾
受保护的MyTableModel doInBackground()引发异常{
//这是一个故意的暂停,以允许UI有时间渲染
《睡眠》(2000年);
ResultSet rs=db.queryTable(查询);
System.out.println(“开始编程”);
while(rs.next()){
logEvent数据=新的logEvent();

对于(int i=0;i我的答案将适用于一般类型的问题,您需要处理非常大的数据集,而不仅仅是特定的“表中的200万行”问题

当您遇到需要操作的数据大于某个容器的问题时(在您的情况下,内存大于系统的物理内存,但这可以应用于任何大于其容器的数据—物理、虚拟、逻辑或其他),您需要创建一种机制,以便在任何给定的时间仅流式传输所需的数据,如果需要缓冲区,则可能需要稍微多一些

例如,如果希望能够在表中显示10行,而数据集太大,则需要创建一个表模型,该模型了解当前显示的10行,并在视图更改时将该数据与所需数据交换。因此,创建一个包含10条记录的表模型,而不是200万条记录。或者对于我提到的可选缓冲,让模型保存30条记录;视图中的10条记录,以及前后的10条记录,这样当用户滚动表格时,您可以立即更改数据,这样小的滚动条增量就具有很高的响应性——那么,只有当用户滚动时,动态流式传输数据的问题才明显ls非常快(即:单击滚动条“thumb”并立即从上到下拖动)

这与压缩算法压缩/解压100GB数据的方式相同;这些数据并不是一次全部存储在内存中。或者,由磁带机支持的软件是如何工作的(它们别无选择,因为它不是随机访问)或者,几乎每个人都熟悉的一个例子:这就是在线视频流的工作原理。想想YouTube和视频底部的加载栏及其灰色缓冲区;如果你“快进”它通常会立即切换到缓冲区中的某个时间,但如果切换到某个时间,则视频可能会在加载下一帧时停止一秒钟(然后缓冲更多)。这也是一个庞大的表的工作原理,只是您正在从任何一帧“流”到数据模型