hutool icon indicating copy to clipboard operation
hutool copied to clipboard

ReentrantCache的clean方法同样可能导致外部资源泄露

Open IcoreE opened this issue 7 months ago • 0 comments

基本原理和https://github.com/chinabugotech/hutool/issues/3957 一样。 ReentrantCache类的clear()源码:


	public void clear() {
		lock.lock();
		try {
			cacheMap.clear();
		} finally {
			lock.unlock();
		}
	}

测试代码

@Test
    public void cacheClearMethodTest() throws Exception {
        Cache<String, Connection> connectionCache = CacheUtil.newLFUCache(3);
        //设置监听器,触发回调释放资源
        connectionCache.setListener(new ConnCacheListener());
        Class.forName("com.mysql.jdbc.Driver");
        Connection connection1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "root");
        Connection connection2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "root");
        connectionCache.put("key1",connection1);
        connectionCache.put("key2",connection2);
        connectionCache.clear();//这行代码导致缓存对象从cache中清除了,但是缓存对象关联的数据库连接永久泄露了。
    }

    class ConnCacheListener implements CacheListener<String,Connection>{
        @Override
        public void onRemove(String key, Connection conn) {
            //监听器,触发回调释放资源
            try {
                if (!conn.isClosed()) {
                    System.out.println("数据库连接资源释放中:"+conn);
                    conn.close(); // 资源手动释放
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

运行截图:cacheMap.size()等于0,但是数据库连接资源泄露

Image

bug原因: cacheMap直接使用的是LinkedHashMap的clear方法,如果cacheMap中存放的是数据库连接资源对象,那么可能导致资源泄露。

提交修复代码: commit

@Override
	public void clear() {
		lock.lock();
		try {
			// 获取所有键的副本
			Set<Mutable<K>> keys = new HashSet<>(cacheMap.keySet());
			for (Mutable<K> key : keys) {
				CacheObj<K, V> co = removeWithoutLock(key.get());
				if (co != null) {
					onRemove(co.key, co.obj); // 触发资源释放
				}
			}
		} finally {
			lock.unlock();
		}
	}

IcoreE avatar Jun 06 '25 07:06 IcoreE