【发布时间】:2010-02-28 12:01:53
【问题描述】:
我的 Java 编写的应用程序消耗了太多内存。
程序如何工作:用户从日历 (GUI) 中选择一个日期,然后应用程序将数据加载到 JTable 组件中。每次加载数据时,都会创建并设置新的 TableModel。没有创建新的 JTable,只创建了模型。
有什么问题?:从日历中选择新的一天并加载到 JTable 会消耗大约 2-3 MB 的内存。 在启动应用程序时消耗 cca 50-60 MB RAM,在日历上“点击”几下(如 20 次)后,应用程序消耗全部堆大小 (128MB)。应用程序崩溃,当然...
我应该怎么做?:我很确定数据库查询没问题。我可能会以某种方式设置更大的堆大小(我用谷歌搜索过,但这只是我的计算机的解决方案,用户不会这样做)或者我应该以某种方式 删除带有数据库数据的旧 TableModel。 但不应该这样垃圾收集器的工作?我可以强制它(System.gc()),但这无济于事......
感谢您的建议!
编辑:处理日历事件的代码(我删除了 Javadoc,它是我的母语)
package timesheet.handlers;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import org.jdesktop.swingx.JXMonthView;
import org.jdesktop.swingx.event.DateSelectionEvent;
import org.jdesktop.swingx.event.DateSelectionListener;
import timesheet.database.WorkerOperations;
import timesheet.frames.WorkerFrame;
import timesheet.logictrier.*;
public class WorkerMonthViewHandler {
private JXMonthView monthView;
private WorkerFrame workerFrame;
private WorkerOperations wops;
private Date[] week = new Date[5];
private WorkerTasksTableHandler wtth;
public WorkerMonthViewHandler(WorkerFrame workerFrame) {
this.workerFrame = workerFrame;
this.monthView = workerFrame.getWorkerMonthView();
wops = workerFrame.getWorkerOperations(); // for DB usage
}
public void initMonthView() {
List<Task> tasks = wops.getWorkerTasks(workerFrame.getWorker()); // db select
for (Task task : tasks) {
if (!monthView.getSelection().contains(task.getPlannedStart())) {
monthView.addFlaggedDates(task.getPlannedStart());
monthView.addFlaggedDates(task.gePlannedEnd()); // not really important
}
}
monthView.setSelectionDate(new Date());
monthView.getSelectionModel().addDateSelectionListener(new DateSelectionListener() {
public void valueChanged(DateSelectionEvent dse) {
Date d = monthView.getSelectionDate();
for (int i=0; i<week.length; i++) {
if (d.equals(week[i])) {
return;
}
}
Calendar cal = new GregorianCalendar();
cal.setTime(d);
long dayMs = 24 * 60 * 60 * 1000;
switch (cal.get(Calendar.DAY_OF_WEEK)) {
case(Calendar.MONDAY) : {
week[0] = new Date(cal.getTimeInMillis());
week[1] = new Date(cal.getTimeInMillis()+dayMs);
week[2] = new Date(cal.getTimeInMillis()+2*dayMs);
week[3] = new Date(cal.getTimeInMillis()+3*dayMs);
week[4] = new Date(cal.getTimeInMillis()+4*dayMs);
} break;
case (Calendar.TUESDAY) : {
week[0] = new Date(cal.getTimeInMillis()-dayMs);
week[1] = new Date(cal.getTimeInMillis());
week[2] = new Date(cal.getTimeInMillis()+1*dayMs);
week[3] = new Date(cal.getTimeInMillis()+2*dayMs);
week[4] = new Date(cal.getTimeInMillis()+3*dayMs);
} break;
case (Calendar.WEDNESDAY) : {
week[0] = new Date(cal.getTimeInMillis()-2*dayMs);
week[1] = new Date(cal.getTimeInMillis()-dayMs);
week[2] = new Date(cal.getTimeInMillis());
week[3] = new Date(cal.getTimeInMillis()+1*dayMs);
week[4] = new Date(cal.getTimeInMillis()+2*dayMs);
} break;
case (Calendar.THURSDAY) : {
week[0] = new Date(cal.getTimeInMillis()-3*dayMs);
week[1] = new Date(cal.getTimeInMillis()-2*dayMs);
week[2] = new Date(cal.getTimeInMillis()-1*dayMs);
week[3] = new Date(cal.getTimeInMillis());
week[4] = new Date(cal.getTimeInMillis()+1*dayMs);
} break;
case (Calendar.FRIDAY) : {
week[0] = new Date(cal.getTimeInMillis()-4*dayMs);
week[1] = new Date(cal.getTimeInMillis()-3*dayMs);
week[2] = new Date(cal.getTimeInMillis()-2*dayMs);
week[3] = new Date(cal.getTimeInMillis()-dayMs);
week[4] = new Date(cal.getTimeInMillis());
} break;
case (Calendar.SATURDAY) : {
week[0] = new Date(cal.getTimeInMillis()-5*dayMs);
week[1] = new Date(cal.getTimeInMillis()-4*dayMs);
week[2] = new Date(cal.getTimeInMillis()-3*dayMs);
week[3] = new Date(cal.getTimeInMillis()-2*dayMs);
week[4] = new Date(cal.getTimeInMillis()-dayMs);
} break;
case (Calendar.SUNDAY) : {
week[0] = new Date(cal.getTimeInMillis()-6*dayMs);
week[1] = new Date(cal.getTimeInMillis()-5*dayMs);
week[2] = new Date(cal.getTimeInMillis()-4*dayMs);
week[3] = new Date(cal.getTimeInMillis()-3*dayMs);
week[4] = new Date(cal.getTimeInMillis()-2*dayMs);
} break;
}
wtth = new WorkerTasksTableHandler(workerFrame,week);
wtth.createTable(); // sets model on JTable
}
});
}
public void reportTask() {
wtth.reportTasks(); // simple DB insert
}
}
使用 NetBeans 分析器: 拍摄日期:2010 年 2 月 28 日星期日 14:25:16 CET 文件:C:...\private\profiler\java_pid4708.hprof 文件大小:72.2 MB
Total bytes: 62 323 264
Total classes: 3 304
Total instances: 1 344 586
Classloaders: 18
GC roots: 2 860
Number of objects pending for finalization: 0
【问题讨论】:
-
你提到了一个数据库......你能告诉我们更多关于它在做什么,你正在使用什么数据库,如果你正在关闭你的结果集等等......似乎更有可能是罪魁祸首。另外,您是否保留对旧模型的任何引用?您将多少数据加载到模型中?你的表有自定义渲染器吗?
-
注意:过去我已经将包含数千行的 JTable TableModels 换掉了......并且从未增加默认的堆大小。所以这里还有别的东西在起作用。
-
更有可能是您的代码而不是 JVM 出现问题。 Java 肯定有错误,但自 Java 1.0 以来就已经找到并修复了一个如此基础的类中的内存“泄漏”。
-
好吧,您可以看到代码,但恐怕您不想:-(很多数据库选择等,我将它们作为查询进行了测试,以查看它们带来正确的结果我使用 MySQL 服务器我不关闭 ResultSets,我应该吗?:) 我不保留对旧模型的引用,如果您的意思是将它们保存到数组或列表中,或者我有 JSpinner 的自定义表格渲染器
-
哦,我不想看代码。那是你的工作。不要关闭结果集?天啊。我希望微笑是讽刺的。如果没有,你应该更仔细地检查你的东西。
标签: java heap-memory