1 Attachment(s)
Database Table Model Does Not Release Memory When Disposed
Hi everyone,
I have a large table which I would like to display using the table model code below. Unfortunately there seems to be a memory-leak of some kind and the memory allocated for the table does not get released after the frame is disposed.
Attachment 4099
When the "Database Shower" frame is closed the memory does not get released as expected but stays the same. I have been looking for the culprit for hours now and would appreciate a push in the right direction. Please see code below..
________________________________________
Code:
package test;
import com.sun.awt.AWTUtilities;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.sql.Connection;
import java.sql.DriverManager;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JFrame;
/**
*
* @author Evan
*/
public class Test extends JFrame implements ActionListener{
JButton jButton = new JButton("Open DB");
JButton jButton2 = new JButton("Close DB");
JPanel panel = new JPanel();
Connection con;
DatabaseShower frame;
public Test()
{
getContentPane().setBackground(new Color(0, 0, 40, 190));
setSize(400,400);
setVisible(true);
setLayout(new GridBagLayout());
add(panel);
jButton.addActionListener(this);
jButton.setActionCommand("open db");
jButton2.addActionListener(this);
jButton2.setActionCommand("close db");
panel.add(jButton);
panel.add(jButton2);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
panel.setBounds(0,0,200,200);
}
@Override
public void paint(Graphics g)
{
Graphics2D g2d2 = (Graphics2D)g;
g2d2.setColor(new Color(255,255,255,100));
g2d2.fillRoundRect(getInsets().left + (getHeight()/200), getInsets().top + (getHeight()/200), getWidth() - (2*(getInsets().left + (getHeight()/200))), getHeight() - (2*(((getInsets().bottom + getInsets().top)) + (getHeight()/200))), 10, 10);
panel.repaint();
}
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals("open db"))
{
try{openDB();}catch(Exception f){}
}
if (e.getActionCommand().equals("close db"))
{
try{frame.data.removeAll(); frame.names.removeAll(); frame.data = null; frame.names = null; frame = null;}catch(Exception f){}
try{con.close();}catch(Exception f){}
}
}
public static void main(String[] args)
{
// TODO code application logic here.
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Test().setVisible(true);
}
});
}
public void openDB() throws Exception
{
Class.forName("org.firebirdsql.jdbc.FBDriver").newInstance();
con = DriverManager.getConnection("jdbc:firebirdsql://localhost:3050/d:/database/pos.gdb", "SYSDBA", "masterke");
String title = "Database Shower";
frame = new DatabaseShower(con, title);
frame.setSize(1024, 768);
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
______________________________________________
Code:
package test;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.DefaultTableModel;
import java.sql.*;
public class DatabaseShower extends JFrame {
protected JList names;
protected JTable data = new JTable();
public DatabaseShower(final Connection con, String title)
throws SQLException {
super(title);
names = new JList(new TableNameListModel(con));
names.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
Object tableName = names.getSelectedValue();
if (tableName != null) {
try {
data.setModel(new DatabaseTableModel(con, tableName));
} catch (SQLException ex) {
ex.printStackTrace();
data.setModel(new DefaultTableModel());
}
}
}
}
});
getContentPane().add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
new JScrollPane(names), new JScrollPane(data)));
}
}
_________________________________________________
Code:
package test;
import org.apache.commons.dbutils.*;
import javax.swing.table.DefaultTableModel;
import java.sql.*;
import java.util.Vector;
public class DatabaseTableModel extends DefaultTableModel {
private final QueryRunner queryRunner = new QueryRunner();
public DatabaseTableModel(Connection con, Object tableName)
throws SQLException {
// might need to delimit table names
String sql = "SELECT * FROM " + tableName;
queryRunner.query(con, sql, new ResultSetHandler() {
public Object handle(ResultSet rs) throws SQLException {
// extract the column names
int numColumns = rs.getMetaData().getColumnCount();
Vector column = new Vector();
for (int i = 1; i <= numColumns; i++) {
column.add(rs.getMetaData().getColumnName(i));
}
// extract the data
Vector data = new Vector();
while (rs.next()) {
Vector row = new Vector();
for (int i = 1; i <= numColumns; i++) {
row.add(rs.getString(i));
}
data.add(row);
}
setDataVector(data, column);
return null;
}
});
}
}
________________________________________________
Code:
package test;
import javax.swing.*;
import java.sql.*;
import java.util.*;
public class TableNameListModel extends AbstractListModel {
private final List listData = new ArrayList();
public TableNameListModel(Connection con) throws SQLException {
ResultSet rs = con.getMetaData().getTables(null,null,null,null);
// you might need a filter here if your database mixes system
// tables with user tables, e.g. Microsoft SQL Server
while (rs.next()) {
listData.add(rs.getString("TABLE_NAME"));
}
rs.close();
}
public int getSize() { return listData.size(); }
public Object getElementAt(int i) { return listData.get(i); }
}
__________________________________________________ _
The database I am using is Firebird.
Any help greatly appreciated..
Re: Database Table Model Does Not Release Memory When Disposed
The Task Manager isn't the right tool to check for a memory leak, simply because memory released by your running program may not be returned to the OS by the JVM.
Use a profiler.
db
Re: Database Table Model Does Not Release Memory When Disposed
Thanks for the response it was very helpful..
It seems that the JVM is reluctant to let go of allocated memory and hangs on to it in case it might be needed again. I do not understand the full concept of it but in my particular case it is not ideal.
I have chosen to take an alternative path and use one java application to open another as follows:
Code:
try
{
String[] command = {"javaw", "-jar", "D:\\netbeans\\test\\dist\\test.jar"};
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(command);
}
catch (IOException f)
{
f.printStackTrace();
}
This way the resources are returned once the second java application terminates.
Re: Database Table Model Does Not Release Memory When Disposed
You could look at the -XXMaxHeapFree as discussed here. This lets you control the maximum % of free heap the JVM will hold onto before shrinking. It defaults to 70%.