java - obtener - ¿Por qué el redimensionamiento de la columna JTable genera basura?
como obtener los valores de un jtable en java (2)
Genera basura simplemente porque puede. Java es un lenguaje recogido de basura, esencialmente todo lo que hace crea basura.
Mientras presiona y arrastra ese botón, java toma la actividad primitiva (es decir, el estado del botón del mouse, el estado de la posición del cursor, la hora, etc.) y crea eventos. Luego compara esa secuencia de eventos con cosas como la posición anterior del cursor, etc. para detectar si el programa realmente quiere hacer algo con esa información. Cuando lo mueva, Java necesita dibujar líneas, rectángulos de archivos, dibujar texto, etc.
Toda esa actividad deja algo, basura, y eventualmente necesita ser recolectada.
Simplemente al estar inactivo, su programa está creando basura, muy probablemente muy lentamente, ya que los temporizadores internos y los que mueren son reciclados. Intenta usar el programa jconsole para ver el montón y verás cómo se arrastra con el tiempo.
Esto es normal y no hay nada de qué preocuparse. Es una característica, no un error.
Actualmente estoy implementando un programa que usa una JTable para mostrar cierta información. La tabla no contiene más de 10 filas (por lo que es pequeña).
Durante el desarrollo, normalmente ejecuto los programas con la opción -verbose:gc
.
Si hago clic en la línea entre 2 columnas y sigo moviéndolo hacia la izquierda, luego hacia la derecha y así sucesivamente, noto que se genera mucha basura. El programa no hace absolutamente nada mientras hago esto , por lo que no hay otra fuente potencial de esta basura. Además, si me detengo, el recolector de basura también deja de recolectar.
Si sigo cambiando el tamaño de estas columnas durante un minuto, se generan aproximadamente 100 MB + de basura , lo que parece mucho.
Esto no afecta el funcionamiento de mi programa, pero parece muy extraño. ¿Por qué se comporta de esta manera?
EDITAR
Aquí hay un SSCCE:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class JTableTest
{
public static void main (String[] args)
{
SwingUtilities.invokeLater (new Runnable ()
{
@Override public void run ()
{
JFrame frame = new JFrame ();
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
frame.setLayout (null);
frame.setSize (700, 300);
frame.setResizable (false);
JTable table = new JTable ();
table.setAutoResizeMode (JTable.AUTO_RESIZE_ALL_COLUMNS);
String[] titles = { "Title 1", "Title 2", "Title 3", "Title 4", "Title 5" };
String[][] data = {
{ "Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3", "Row 1, Column 4", "Row 1, Column 5"},
{ "Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3", "Row 2, Column 4", "Row 2, Column 5"},
{ "Row 3, Column 1", "Row 3, Column 2", "Row 3, Column 3", "Row 3, Column 4", "Row 3, Column 5"},
{ "Row 4, Column 1", "Row 4, Column 2", "Row 4, Column 3", "Row 4, Column 4", "Row 4, Column 5"},
{ "Row 5, Column 1", "Row 5, Column 2", "Row 5, Column 3", "Row 5, Column 4", "Row 5, Column 5"}
};
table.setModel (new DefaultTableModel (data, titles)
{
@Override public boolean isCellEditable (int row, int column)
{
return false;
}
});
JScrollPane scrollpane = new JScrollPane (table);
scrollpane.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollpane.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scrollpane.setBounds (20, 20, 650, 250);
frame.add (scrollpane);
frame.setVisible (true);
}
});
}
}
Ejecute el programa con la opción -verbose:gc
. Cuando se ejecuta, haga clic entre "Título x" y "Título y" (x! = Y) y cambie el tamaño de esas columnas. Mantenga el mouse presionado y muévalo a izquierda y derecha. Verás en la stdout
que el recolector de basura está recogiendo basura mientras haces esto. (en mi sistema está haciendo esto unas 10 veces / minuto). Si / cuando se detiene, no se recoge más basura.
Por favor
algunos cambios en el código
se agregó JTextArea
¿Nos confirmas que tu salida es la misma que la salida impresa en JTextArea?
(WinXP, Java6 -> parece como siempre)
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.DefaultCaret;
public class JTableTest {
private javax.swing.Timer timer = null;
private JTextArea text = new JTextArea();
public JTableTest() {
String[] titles = {"Title 1", "Title 2", "Title 3", "Title 4", "Title 5"};
String[][] data = {
{"Row 1, Column 1", "Row 1, Column 2", "Row 1, Column 3", "Row 1, Column 4", "Row 1, Column 5"},
{"Row 2, Column 1", "Row 2, Column 2", "Row 2, Column 3", "Row 2, Column 4", "Row 2, Column 5"},
{"Row 3, Column 1", "Row 3, Column 2", "Row 3, Column 3", "Row 3, Column 4", "Row 3, Column 5"},
{"Row 4, Column 1", "Row 4, Column 2", "Row 4, Column 3", "Row 4, Column 4", "Row 4, Column 5"},
{"Row 5, Column 1", "Row 5, Column 2", "Row 5, Column 3", "Row 5, Column 4", "Row 5, Column 5"}
};
JTable table = new JTable();
table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
table.setModel(new DefaultTableModel(data, titles) {
private static final long serialVersionUID = 1L;
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
});
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollpane = new JScrollPane(table);
scrollpane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollpane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
DefaultCaret caret = (DefaultCaret) text.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
JScrollPane scroll = new JScrollPane(text);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocation(150, 150);
frame.setSize(700, 300);
frame.setResizable(false);
frame.add(scrollpane, BorderLayout.NORTH);
frame.add(scroll, BorderLayout.CENTER);
frame.setVisible(true);
start();
}
private void start() {
timer = new javax.swing.Timer(1000, updateCol());
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
text.append("FreeMemory in Kb " + Runtime.getRuntime().freeMemory() / 1000 + "/n");
text.append("MaxMemory in Kb " + Runtime.getRuntime().maxMemory() / 1000 + "/n");
text.append("TotalMemory in Kb " + Runtime.getRuntime().totalMemory() / 1000 + "/n");
text.append("UsedMemory in Kb " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000) + "/n");
text.append("/n");
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JTableTest jTableTest = new JTableTest();
}
});
}
}
EDITAR JTable y GC algunas columnas con 75k filas (82 -85Mb)
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
public class TriState extends JPanel {
private static final long K = 1024;
private static final long M = K * K;
private static final long G = M * K;
private static final long T = G * K;
protected static int ctr = 1;
private static final long serialVersionUID = 1L;
private JButton btnShow = new JButton("Show Form");
private JLabel lblMem = new JLabel();
private static final DecimalFormat df = new DecimalFormat("#,##0.#");
protected Timer updateTimer = new Timer();
public TriState() {
this.setLayout(new GridLayout());
add(btnShow);
add(lblMem);
updateTimer.scheduleAtFixedRate(new UpdateTimerTask(), 1000, 1000);
btnShow.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FrmReferrals fr = new FrmReferrals();
fr.setVisible(true);
}
});
}
class UpdateTimerTask extends TimerTask {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
dumpMemoryUsage();
}
});
}
}
protected void dumpMemoryUsage() {
System.gc();
Long t = Runtime.getRuntime().totalMemory();
long f = Runtime.getRuntime().freeMemory();
String st = convertToStringRepresentation(t);
String sf = convertToStringRepresentation(f);
String su = convertToStringRepresentation(t - f);
System.out.println("Total:" + st + "(" + t + ") Free:" + sf + "(" + f + ") Used:" + su + "(" + (t - f) + ")");
lblMem.setText(su + "/" + st);
}
public static String convertToStringRepresentation(final long value) {
final long[] dividers = new long[]{T, G, M, K, 1};
final String[] units = new String[]{"TB", "GB", "MB", "KB", "B"};
if (value < 1) {
throw new IllegalArgumentException("Invalid file size: " + value);
}
String result = null;
for (int i = 0; i < dividers.length; i++) {
final long divider = dividers[i];
if (value >= divider) {
final double dr = divider > 1 ? (double) value / (double) divider : (double) value;
result = df.format(dr) + units[i];
break;
}
}
return result;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("SimpleTableDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create and set up the content pane.
TriState newContentPane = new TriState();
newContentPane.setOpaque(true); // content panes must be opaque
frame.setContentPane(newContentPane);
// Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
protected class PopupMenu extends JPopupMenu {
public PopupMenu() {
JRadioButtonMenuItem item1 = new JRadioButtonMenuItem(new AbstractAction("Insert Item") {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
item1.setActionCommand("Insert");
add(item1);
JRadioButtonMenuItem item2 = new JRadioButtonMenuItem(new AbstractAction("Delete Item") {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
item2.setActionCommand("Delete");
add(item2);
}
}
public class FrmReferrals extends JFrame {
public FrmReferrals() {
super();
init();
}
protected void init() {
jbInit();
}
protected void closeIt() {
uninit();
}
// variables here
final Dimension dimPreferred = new Dimension(1270, 995);
final JTabbedPane tabbedPane = new JTabbedPane();
private JTable tblReferrals = null;
private PopupMenu popMenu = new PopupMenu();
protected void jbInit() {
setPreferredSize(dimPreferred);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setTitle("Referrals");
JPanel pnl = new JPanel();
pnl.setOpaque(false);
pnl.setLayout(new BorderLayout());
pnl.add(tabbedPane, BorderLayout.CENTER);
// put it all in the frame
add(pnl);
pack();
setLocationRelativeTo(null);
// init the table and model
ReferralsTableModel ctm = new ReferralsTableModel(buildDummyVector());
tblReferrals = new JTable(ctm);
tblReferrals.setComponentPopupMenu(popMenu);
tblReferrals.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
tabbedPane.add(new JScrollPane(tblReferrals, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED));
addWindowListener(new WindowListener() {
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
closeIt();
}
@Override
public void windowDeactivated(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowOpened(WindowEvent e) {
}
});
}
protected Vector<DBO_Referrals> buildDummyVector() {
Vector<DBO_Referrals> vr = new Vector<DBO_Referrals>();
for (int x = 0; x < 75000; x++) {
DBO_Referrals r = new DBO_Referrals(x + (5000 * ctr));
vr.add(r);
}
return vr;
}
protected void uninit() {
tblReferrals.setComponentPopupMenu(null);
for (Component c : popMenu.getComponents()) {
PropertyChangeListener[] pl = c.getPropertyChangeListeners();
for (PropertyChangeListener l : pl) {
c.removePropertyChangeListener(l);
}
if (c instanceof JMenuItem) {
ActionListener[] al = ((JMenuItem) c).getActionListeners();
for (ActionListener l : al) {
((JMenuItem) c).removeActionListener(l);
}
}
}
popMenu = null;
}
protected class DBO_Referrals {
private long id;
private String Employee;
private String Rep;
private String Asst;
private String Client;
private String Dates;
private String Status;
private String Home;
public DBO_Referrals(long id) {
this.id = id;
Employee = "Employee" + id;
Rep = "Rep" + id;
Asst = "Asst" + id;
Client = "Client" + id;
Dates = "Dates" + id;
Status = "Status" + id;
Home = "Home" + id;
}
public long getId() {
return id;
}
public String getEmployee() {
return Employee;
}
public String getRep() {
return Rep;
}
public String getAsst() {
return Asst;
}
public String getClient() {
return Client;
}
public String getDates() {
return Dates;
}
public String getStatus() {
return Status;
}
public String getHome() {
return Home;
}
}
public class ReferralsTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector<DBO_Referrals> data = new Vector<DBO_Referrals>();
final String[] sColumns = {"id", "Employee", "Rep", "Assistant", "Client", "Date", "Status", "Home", "R"};
public ReferralsTableModel() {
super();
}
public ReferralsTableModel(Vector<DBO_Referrals> data) {
this();
this.data = data;
}
@SuppressWarnings("unchecked")
@Override
public Class<?> getColumnClass(int col) {
switch (col) {
case 0:
return Long.class;
default:
return String.class;
}
}
@Override
public int getColumnCount() {
return sColumns.length;
}
@Override
public int getRowCount() {
return data.size();
}
@Override
public Object getValueAt(int row, int col) {
if (row > data.size()) {
return null;
}
DBO_Referrals a = data.get(row);
switch (col) {
case 0:
return a.getId();
case 1:
return a.getEmployee();
case 2:
return a.getRep();
case 3:
return a.getAsst();
case 4:
return a.getClient();
case 5:
return a.getDates();
case 6:
return a.getStatus();
case 7:
return a.getHome();
case 8:
return "+";
default:
return null;
}
}
}
}
}