Java 如何加载200万行的JTable
我正在编写一个应用程序,它使用JTable来显示日志文件的行。我已经解析了数据,但是当我尝试将行添加到AbstractTableModel时,我收到“超出gc开销限制”或“java.lang.OutOfMemoryError:java堆空间”错误。是否需要配置垃圾收集器或更改AbstractTableModel以允许我加载所需的行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
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和视频底部的加载栏及其灰色缓冲区;如果你“快进”它通常会立即切换到缓冲区中的某个时间,但如果切换到某个时间,则视频可能会在加载下一帧时停止一秒钟(然后缓冲更多)。这也是一个庞大的表的工作原理,只是您正在从任何一帧“流”到数据模型