Memory leak while reading Bytes from MySQL table...
Terve !
i am writing a little application that read/writes image data from/to a database. when running the application,it is using more and more memory and the method causing this is the method listed below(getBytesOfView). After calling this method 470 times the Error occurs ( the application is not using this method that excessive like in the sample code below, but still i have this memory leak) .
So, if someone could tell me why i am always ending up in a OutOfMemoryError after running this little piece of code or even could tell me how to AVOID this Error ... that would be "awesome".
Thanks in advance! Robert
about the DB: i am using a MySQL database; the datatype of the column i am reading is a longblob (since i store image data in this column);
my troubleshooting-find-the-memory-leak-code:
publicbyte[] getBytesOfView(String partID, String perspective){
if(connected){
try{
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT `data` FROM `view` WHERE partID = '"+partID+"' AND perspective = '"+perspective+"'");
if(rs.next()){
return rs.getBytes("data");
}
}catch (SQLException ex){
ex.printStackTrace();
returnnull;
}
}
returnnull;
}
publicstaticvoid main(String []args){
AccessDB accessdb =new AccessMySQL();
accessdb.establishDBConnection();
byte[] Bytes;
for(int i = 0 ; i < 1000 ; i++){
Bytes = accessdb.getBytesOfView("piratesship_plank","top");
if(Bytes==null)
System.out.println(i+". run = NULL");
else
System.out.println(i+". run len="+Bytes.length);
}
}
the output:
[...]
467. run len=138070
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
468. run len=138070
469. run len=138070
470. run len=138070
471. run len=138070
472. run len=138070
Java Result: 1
[3274 byte] By [
roberta] at [2007-10-2 17:48:55]

In addition to Stu Derby's usual impeccable advice, I'd add the following: Close those resources in a finally block in their own individual try/catch blocks. That way you can still try to close a statement even if the result set throws an exception.
I have a utility class with static helper methods, like this:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* Common database utilities Insured: MD87020 Date: Apr 24, 2005 Time: 10:26:53 AM
*/
public final class DbUtils
{
/**
* Logger for the class
*/
private static final Log logger = LogFactory.getLog(DbUtils.class);
/**
* Get a database connection
* @param is for reading a Properties file with name, value pairs for driver, url, username, and password.
* @return connection to the database
* @throws IllegalArgumentException if the input stream is null
* @throws IOException if the read fails
* @throws SQLException if the connection fails
*/
public static final Connection getConnection(InputStream is)
throws IOException, SQLException
{
if (is == null)
{
throw new IllegalArgumentException("Input stream cannot be null");
}
Connection connection = null;
try
{
Properties properties = new Properties();
properties.load(is);
connection = getConnection(properties);
}
catch (SQLException e)
{
logger.error("Could not open connection", e);
throw e;
}
catch (IOException e)
{
logger.error("Could not read properties", e);
throw e;
}
return connection;
}
/**
* Create a database connection
* @param properties containing name, value pairs for driver, url, username, password
* @return connection to the database
* @throws SQLException if the connection fails
*/
public static final Connection getConnection(Properties properties)
throws SQLException
{
return getConnection(properties.getProperty("driver"),
properties.getProperty("url"),
properties.getProperty("username"),
properties.getProperty("password"));
}
/**
* Create a connection to a database
* @param driver
* @param url
* @param username
* @param password
* @return connection to the database
* @throws SQLException if the connection fails
*/
public static final Connection getConnection(final String driver,
final String url,
final String username,
final String password)
throws SQLException
{
Connection connection = null;
try
{
Class.forName(driver).newInstance();
connection = DriverManager.getConnection(url, username, password);
}
catch (Exception e)
{
String message = "Could not open connection";
logger.error(message, e);
throw new SQLException(message);
}
return connection;
}
/**
* Perform a JNDI lookup to get a database connection
* @param jndiLookupName
* @return database connection
* @throws NamingException if the context lookup fails
* @throws SQLException if the connection fails
*/
public static final Connection getConnection(final String jndiLookupName)
throws NamingException, SQLException
{
Connection connection = null;
InitialContext context = null;
try
{
context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup(jndiLookupName);
connection = dataSource.getConnection();
}
catch (NamingException e)
{
logger.error("Could not obtain naming context", e);
throw e;
}
catch (Exception e)
{
String message = "Could not open connection";
logger.error(message, e);
throw new SQLException(message);
}
finally
{
close(context);
}
return connection;
}
/**
* Close a naming context
* @param namingContext to close
*/
public static final void close(Context namingContext)
{
if (namingContext != null)
{
try
{
namingContext.close();
}
catch (NamingException ignore)
{
logger.error("Could not close naming context", ignore);
}
}
}
/**
* Close a statement and result set
* @param statement
* @param rs
*/
public static final void close(Statement statement, ResultSet rs)
{
close(rs);
close(statement);
}
/**
* Close a connection and statement
* @param connection
* @param statement
*/
public static final void close(Connection connection, Statement statement)
{
close(statement);
close(connection);
}
/**
* Close a statement, connection, and result set
* @param connection
* @param statement
* @param rs
*/
public static final void close(Connection connection,
Statement statement,
ResultSet rs)
{
close(rs);
close(statement);
close(connection);
}
/**
* Close a ResultSet
* @param rs to close
*/
public static final void close(ResultSet rs)
{
if (rs != null)
{
try
{
rs.close();
}
catch (SQLException ignore)
{
logger.error("could not close result set", ignore);
}
}
}
/**
* Close a statement
* @param statement to close
*/
public static final void close(Statement statement)
{
if (statement != null)
{
try
{
statement.close();
}
catch (SQLException ignore)
{
logger.error("could not close statement", ignore);
}
}
}
/**
* Close a Connection
* @param connection to close
*/
public static final void close(Connection connection)
{
if (connection != null)
{
try
{
connection.close();
}
catch (SQLException ignore)
{
logger.error("could not close connection", ignore);
}
}
}
/**
* Convenience method for rolling back a connection
* @param connection to rollback
*/
public static void rollback(Connection connection)
{
if (connection != null)
{
try
{
connection.rollback();
}
catch (SQLException e)
{
logger.error("could not rollback connection", e);
}
}
}
}
%