2

現在、JTable を使用して情報を表示するプログラムを実装しています。テーブルに含まれる行は 10 行以下です (小さいため)。

開発中は、通常、-verbose:gcオプションを使用してプログラムを実行します。

2 つの列の間の線をクリックして、左に移動し、次に右に移動し続けると、大量のゴミが生成されることに気付きます。私がこれをしている間、プログラムはまったく何もしないので、このガベージの潜在的な原因は他にありません。また、私が止めるとガベージコレクタも収集を止めます。

これらの列のサイズを 1 分ほど変更し続けると、約100MB 以上のガベージが生成されます。

これは私のプログラムの実行方法には影響しませんが、非常に奇妙に思えます。なぜこのように振る舞うのですか?

編集

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);
            }
        });
    }
}

オプションを指定してプログラムを実行し-verbose:gcます。実行中、「タイトル x」と「タイトル y」(x != y) の間をクリックして、これらの列のサイズを変更します。マウスをクリックしたまま、左右に動かし続けます。stdoutこれを行っている間、ガベージ コレクターがガベージを収集していることがわかります。(私のシステムでは、これを約10回/分実行しています)。停止すると、ガベージは収集されなくなります。

4

2 に答える 2

3

お願いします

  • コードのいくつかの変更

  • JTextAreaを追加

  • 出力が JTextArea に出力された出力と同じであることを確認しますか?

(WinXP、Java6 --> 永遠のように見えます)

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();
            }
        });
    }
}

JTable を編集し、75k 行 (82 -85Mb) のいくつかの列を GC します。

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;
                }
            }
        }
    }
}
于 2012-04-09T13:37:56.650 に答える
3

それができるという理由だけでゴミを生成します。Java は Garbage Collected 言語であり、基本的に Java が行うすべてのことはゴミを作成します。

そのボタンを押したままドラッグしている間、Java はプリミティブ アクティビティ (つまり、マウス ボタンのステータス、カーソル位置のステータス、時間など) を取得し、イベントを作成します。次に、そのイベントのストリームを古いカーソル位置などと比較して、プログラムが実際にその情報で何かをしたいかどうかを検出します。移動する場合、Java は線を描画したり、四角形をファイルしたり、テキストを描画したりする必要があります。

これらの活動はすべてゴミを置き去りにし、最終的には収集する必要があります。

アイドル状態にあるだけで、内部タイマーなどが死んでリサイクルされるため、プログラムはおそらく非常にゆっくりとガベージを作成しています。jconsole プログラムを使用してヒープを観察してみてください。

これは正常であり、心配する必要はありません。これは機能であって、バグではありません。

于 2012-04-09T14:00:04.520 に答える