我创建了一个GUI(Eclipse向导),用户可以在其中登录数据库。我将db-access交换为外部线程。当用户输入一些文本时,从侦听器调用方法startDBCheck()
。这是代码:
public class DBPage
extends MyWizardPage
{
public final class ConnectionCheckingThread
extends Thread
{
boolean interrupted;
@Override
public void run()
{
updateStatus("Checking connection..."); // Method in MyWizardPage using Display.getDefault().asyncExec() to make changes to the GUI
String dbError = Database.getInstance().checkDBAccess(); //checkDBAccess() is synchronized
if (interrupted)
return;
if (dbError != null)
{
updateStatus("Error connecting database: " + dbError);
return;
}
updateStatus(null);
}
public void disable()
{
interrupted = true;
}
}
private ConnectionCheckingThread connectionCheckingThread;
private void startDBCheck()
{
if (connectionCheckingThread != null)
connectionCheckingThread.disable();
connectionCheckingThread = new ConnectionCheckingThread();
connectionCheckingThread.start();
}
}
我正在观察内存使用情况,并注意到eclipse实例在图形界面上的每次更改都占用了更多内存。如果我玩GUI一段时间,我会得到一个OutOfMemoryError
。这让我觉得垃圾收集器由于某种原因没有删除死线程。我的代码中没有看到任何问题。如果我将connectionCheckingThread上的引用设置为新线程,则没有其他引用指向旧线程,因此应将其删除。我是对的,内存泄漏在其他地方,或者这部分代码真的有问题吗?
upd:我收到PermGen space
错误,这让我想一想这段代码是否可疑。
private synchronized Connection getConnection()
throws Exception
{
// load JDBC drivers from jar file
File driverFile = new File(pathToJar);
URL[] urls = {driverFile.toURI().toURL()};
URLClassLoader child = new URLClassLoader(urls, this.getClass().getClassLoader());
Class< ? > clazz = Class.forName(className, true, child);
if (clazz != null)
{
Driver driver = (Driver)clazz.newInstance();
delegatingDriver.setDriver(driver);
DriverManager.registerDriver(delegatingDriver);
}
// Open a connection. If no exception is thrown, the settings work
return DriverManager.getConnection(dbURL, dbUser, dbPassword);
}
upd2:类加载绝对是原因。现在我需要找出解决方法。
答案 0 :(得分:0)
我决定不再使用DelegatingDriver和DriverManager了。另外,我创建了URLClassLoader
的子类,以便可以动态添加URL。这是我的解决方案:
public class Database
{
private static final class InstanceHolder
{
static final Database INSTANCE = new Database();
}
private static final class DynamicURLClassLoader
extends URLClassLoader
{
public DynamicURLClassLoader(URL[] urls, ClassLoader parent)
{
super(urls, parent);
}
@Override
protected void addURL(URL url)
{
super.addURL(url);
}
}
// skipped
private DynamicURLClassLoader childClassloader;
private Database()
{
childClassloader = new DynamicURLClassLoader(new URL[]{}, this.getClass().getClassLoader());
}
public static Database getInstance()
{
return InstanceHolder.INSTANCE;
}
private synchronized Connection getConnection()
throws Exception
{
// load JDBC drivers from jar file
File driverFile = new File(pathToJar);
childClassloader.addURL(driverFile.toURI().toURL());
java.util.Properties info = new java.util.Properties();
if (dbUser != null)
{
info.put("user", dbUser);
}
if (dbPassword != null)
{
info.put("password", dbPassword);
}
if (dbURL == null)
{
throw new SQLException("The url cannot be null", "08001");
}
Class< ? > clazz = Class.forName(className, true, childClassloader);
if (clazz != null)
{
Driver driver = (Driver)clazz.newInstance();
// Open a connection. If no exception is thrown, the settings work
Connection con = driver.connect(dbURL, info);
if (con != null)
// Success!
return (con);
}
throw new SQLException("The chosen driver is not suitable for " + dbURL, "08001");
}
}