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中存储了实际的连接吗?如果是这样的话,这是一种非常危险的模式,原因有很多(我马上想到了可伸缩性)。您能否改进格式,以便我们可以看到您的要求?