内存泄漏:线程对象未被GC拾取或是否是类加载问题?

时间:2014-07-23 11:01:38

标签: java multithreading memory-leaks garbage-collection

我创建了一个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:类加载绝对是原因。现在我需要找出解决方法。

1 个答案:

答案 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");
    }
}