Java 正在加载只有静态方法的类

Java 正在加载只有静态方法的类,java,jdbc,Java,Jdbc,我有一个类MyClass,它有一个静态变量。类实现类似smth的单例(它将java.sql.DataSource作为静态变量,并具有方法getConnection(),该方法检查DataSource变量是否为null,如果为null-获取连接,否则-返回DataSource.getConnection()) 当我第一次调用MyClass.getConnection()方法时,类被加载到内存中,并获得数据源变量。当程序运行时,该类将留在内存中,还是当程序的控制流在调用了MyClass.getCon

我有一个类
MyClass
,它有一个静态变量。类实现类似smth的单例(它将
java.sql.DataSource
作为静态变量,并具有方法
getConnection()
,该方法检查DataSource变量是否为null,如果为null-获取连接,否则-返回
DataSource.getConnection()
) 当我第一次调用
MyClass.getConnection()
方法时,类被加载到内存中,并获得数据源变量。当程序运行时,该类将留在内存中,还是当程序的控制流在调用了
MyClass.getConnection()
的方法之外退出时,该类将被垃圾收集? 实际上,我想知道我是否必须在每个方法中获取连接对象(获取连接对象是一个相当长的操作,不是吗?)我在哪里使用它,或者在某个地方只使用一次

编辑 这是我获得连接的类

public class ResourceManager {

    private static DataSource dataSource;


    public static synchronized Connection getConnection() throws NamingException, SQLException {
        if (dataSource == null) {
            Locale.setDefault(Locale.ENGLISH);
            Context context = (Context) new InitialContext().lookup("java:comp/env");
            dataSource = (DataSource) context.lookup("jdbc/Project");
            context.close();
        }
        return dataSource.getConnection();
    }


    public static void close(Connection con) {
        if (con != null)
            try {
            con.close();
        } catch (SQLException ex) {
            Logger.getLogger(ResourceManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


    public static void close(ResultSet rs) {
        if (rs != null)
            try {
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(ResourceManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }


    public static void close(PreparedStatement stmt) {
        if (stmt != null)
            try {
            stmt.close();
        } catch (SQLException ex) {
            Logger.getLogger(ResourceManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
在这个类中,我从tomcat池获得连接

因此,如果在一个方法中调用resourcemanager.getConnection()并获得数据源,那么在经过一段时间后调用此方法时,它是同一个数据源还是GC

另外,我在finally块中使用close方法

这节课会留在记忆中吗 程序正在运行,否则将被删除 控件运行时收集的垃圾 程序流将从外部退出 方法在哪里 是否调用了MyClass.getConnection()

当不存在对类对象的引用时,类对象将像任何其他对象一样有资格进行垃圾收集。通常,这些引用由首先加载类的类加载器持有。因此,只要引用该类的类加载器在使用中,该类就会一直存在。除非类加载器是由调用方创建的,并且对类加载器的引用不再存在,否则在方法执行后不会卸载该类加载器

在长时间运行的应用程序(如JavaEE应用程序)中,类和类加载器(每个应用程序通常都有一个唯一的类加载器)将无法进行垃圾收集,直到应用程序本身被关闭

单态模式及其对GC的影响

实现singleton模式的类的垃圾收集是一种独特的情况。该类将继续被其实例引用,因此它将永远无法进行垃圾收集。这可能会导致类加载器本身无法被垃圾收集的问题,特别是在容器中的应用程序重新启动期间,从而导致内存泄漏。防止此类问题的解决方案是在侦听上下文(应用程序)销毁事件的上下文侦听器中销毁singleton实例

更新#2

更新后的问题:

实际上,我想知道我是否必须在每个方法中获取连接对象(获取连接对象是一个相当长的操作,不是吗?)我在哪里使用它,或者在某个地方只使用一次


获取连接的成本很高,但只有在您管理连接的情况下才能实现。这就是为什么要使用连接池支持的数据源。每次需要连接时,数据源都会从池中获取一个连接。连接完成后,应将其关闭,以便将其返回到池中。我的建议是不要过早地进行优化;连接池是现代JavaEE应用程序中的一个事实,应用程序服务器执行足够的优化以确保这里的延迟非常小。依我看,一个经过适当调优的池将比一个手工制作的类提供更好的性能,该类用于集中对连接对象的访问。

当您处理静态方法等时,它们不属于实例。因此,在收集实例时不会对它们进行垃圾收集。相反,它们会留在记忆中。理论上,它们应该保留在内存中,直到相关应用程序终止。只要它继续运行,静态项就会保留在内存中


这对你意味着什么?如果要关闭应用程序,则将单例设置为收集,并在某个时间点收集。否则,它会留在那里。

我认为这是不对的。默认情况下,JVM将GC未使用的类。但是静态变量是一个GC根,所以一旦初始化了一个带有单例的类,它就不会被GC,因为单例将是该类的一个实例。将singleton设置为null,如果没有其他实例,则可以对该类进行GC。您最好创建一个获得连接的单例。但是,不要忘记使用cleanup方法和/或将release连接放在finalize()方法中,这样就可以在singleton集合上正确地释放它。您最好使用一个常规类,而不是尝试使用静态类做一些花哨的事情。相信我。我只是做了一些我正在做的事情。常规实例化类更干净。@Duncan,JLS仅在类加载器符合回收条件时才允许回收类:
Java编程语言的实现可以卸载类。当且仅当其定义类加载器可由垃圾收集器回收时(如§12.6所述),类或接口可被卸载。
@Duncan,您是对的,但是,考虑到单例的存在,除非应用程序的关闭过程将使singleton实例无效,否则该类本身将永远无法进行回收。@Chris:你的意思是说在singleton中存储了实际的连接吗?如果是这样的话,这是一种非常危险的模式,原因有很多(我马上想到了可伸缩性)。您能否改进格式,以便我们可以看到您的要求?