【发布时间】:2020-09-03 11:44:31
【问题描述】:
我需要在 JTable 中显示多行内容。实际内容是在自定义模型中维护的对象集合,它扩展 DefaultTableModel 并通过覆盖 getValueAt() 动态生成单元格内容。
为了多行内容,我实现了自定义TableCellRenderer:
private class MultiLineCellRenderer extends JTextArea implements TableCellRenderer {
public MultiLineCellRenderer() {
setLineWrap(true);
setWrapStyleWord(true);
setOpaque(true);
setBorder(new EmptyBorder(-1, 2, -1, 2));
setRows(1);
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
String text = value == null ? "" : value.toString();
if (!getText().equals(text)) {
setText(text);
int newHeight = table.getRowHeight() * getLineCount();
if (table.getRowHeight(row) != newHeight)
table.setRowHeight(row, newHeight);
}
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
return this;
}
}
现在,如果我用几百行(列数为 2)填充表,我看到 AWT 工作线程开始最大限度地使用一个 CPU 内核。同时,内存消耗从约 100 MB 增加到该数量的十倍甚至更多。即使应用程序实际上没有做任何事情(没有在后台加载数据,没有用户交互)并且只有在我清除表从中获取其内容的集合时才会停止,也会发生这种情况。
通过注释掉选定的代码部分,我将这些行确定为罪魁祸首:
int newHeight = table.getRowHeight() * getLineCount();
if (table.getRowHeight(row) != newHeight)
table.setRowHeight(row, newHeight);
如果我注释掉这一部分,所有表格行都具有相同的高度(1 行文本),但内存消耗保持在 ~100 MB 左右。
如果我将这些行替换为对 table.setRowHeight(row, 32) 的一次调用,即使用固定值,内存消耗将再次无限期地上升。
以下修改有效,代价是所有行都具有相同的高度:
int newHeight = getRowHeight() * getLineCount();
if (table.getRowHeight() < newHeight)
table.setRowHeight(newHeight);
底线:似乎在 JTable 中设置单独的行高会造成大量内存泄漏。我做错了什么,还是我遇到了实际的错误?在后一种情况下,是否有任何已知的修复/解决方法?
【问题讨论】:
-
我看到 AWT 工作线程开始最大限度地使用一个 CPU 核心。 - 更改 JTable 的属性将导致表重新绘制自身。您可能会陷入无限循环。您是否验证过调用
table.setRowHeight(…)方法的频率?发布 minimal reproducible example 来展示您的问题。 -
您使用什么监控工具显示高内存使用情况?另外,正如@camickr 所说,没有minimal reproducible example,我们所能做的就是猜测。
-
table.setRowHeight(…)每当MultiLineCellRenderer#getTableCellRendererComponent()被调用或Swing 在内部调用它时都会被调用。我不会在我的代码中的其他任何地方调用它。
标签: java swing memory-leaks jtable