java - Spring + MongoDB : potential memory leak messages

标签 java spring mongodb memory-leaks

今天我试图修复我的网络应用程序中一些潜在的内存泄漏。

我使用以下库。

  • spring-webmvc-3.2.9.RELEASE
  • spring-data-mongodb-1.5.0.RELEASE
  • mongo-java-driver-2.12.1

首先,我错过了关闭 MongoClient 的机会,但以这种方式更改了我的配置。

@Configuration
public class MongoDBConfiguration implements DisposableBean {
    private MongoClient mongoClient;

    @Bean
    public MongoTemplate mongoTemplate() {
        try {
            final Properties props = loadProperties();
            log.debug("Initializing Mongo DB client");
            mongoClient =
                    new MongoClient(getProperty(props, "host", "localhost"), cint(getProperty(props, "port",
                            "27017")));
            UserCredentials credentials = null;
            final String auth = getProperty(props, "auth", null);
            if (auth != null && auth.equalsIgnoreCase("true")) {
                final String user = getProperty(props, "user", null);
                final String pass = getProperty(props, "pass", null);
                if (user != null && pass != null) {
                    credentials = new UserCredentials(user, pass);
                }
            }
            final MongoDbFactory mongoDbFactory =
                    new SimpleMongoDbFactory(mongoClient, getProperty(props, "dbname", "Feeder"), credentials);
            final MappingMongoConverter mongoConverter =
                    new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory),
                            new MongoMappingContext());
            mongoConverter.setCustomConversions(customConversions(mongoConverter));
            mongoConverter.afterPropertiesSet();
            final MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, mongoConverter);
            return mongoTemplate;
        } catch (final IOException e) {
            log.error("", e);
        }
        return null;
    }

    /**
     * close Mongo client to avoid memory leaks
     */
    @Override
    public void destroy() {
        log.debug("Shutdown Mongo DB connection");
        mongoClient.close();
        log.debug("Mongo DB connection shutdown completed");
    }
}

停止或重新加载 Web 应用程序时,仍有消息提示可能存在内存泄漏。

2014-06-24 07:58:02,114 DEBUG d.p.f.s.m.MongoDBConfiguration - Shutdown Mongo DB connection
2014-06-24 07:58:02,118 DEBUG d.p.f.s.m.MongoDBConfiguration - Mongo DB connection shutdown completed
Jun 24, 2014 7:58:02 AM org.apache.catalina.loader.WebappClassLoader checkThreadLocalMapForLeaks
SEVERE: The web application [/feeder##1.5.1] created a ThreadLocal with key of type [com.mongodb.BaseCluster$1] (value [com.mongodb.BaseCluster$1@766465]) and a value of type [java.util.Random] (value [java.util.Random@5cb9231f]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

第 3 行和第 4 行最多重复 9 次,这是我见过的票价。

我该如何解决这个问题?可以忽略吗?

最佳答案

您需要清理线程局部变量。在这里查看我的答案 stop/interrupt a thread after jdbc Driver has been deregister

/**
 * Cleanup function which cleans all thread local variables. Using thread
 * local variables is not a good practice but unfortunately some libraries
 * are still using them. We need to clean them up to prevent memory leaks.
 * 
 * @return number of Thread local variables
 */
private int immolate() {
    int count = 0;
    try {
        final Field threadLocalsField = Thread.class
                .getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        final Field inheritableThreadLocalsField = Thread.class
                .getDeclaredField("inheritableThreadLocals");
        inheritableThreadLocalsField.setAccessible(true);
        for (final Thread thread : Thread.getAllStackTraces().keySet()) {
            count += clear(threadLocalsField.get(thread));
            count += clear(inheritableThreadLocalsField.get(thread));
        }
        log.info("Immolated " + count + " values in ThreadLocals");
    } catch (Exception e) {
        log.error("ThreadLocalImmolater.immolate()", e);
    }
    return count;
}

/**
 * Cleaner for thread local map.
 * 
 * @param threadLocalMap
 *            thread local map to clean or null
 * @return number of cleaned objects
 * @throws Exception
 *             in case of error
 */
private int clear(@NotNull final Object threadLocalMap) throws Exception {
    if (threadLocalMap == null) {
        return 0;
    }
    int count = 0;
    final Field tableField = threadLocalMap.getClass().getDeclaredField(
            "table");
    tableField.setAccessible(true);
    final Object table = tableField.get(threadLocalMap);
    for (int i = 0, length = Array.getLength(table); i < length; ++i) {
        final Object entry = Array.get(table, i);
        if (entry != null) {
            final Object threadLocal = ((WeakReference<?>) entry).get();
            if (threadLocal != null) {
                log(i, threadLocal);
                Array.set(table, i, null);
                ++count;
            }
        }
    }
    return count;
}

关于java - Spring + MongoDB : potential memory leak messages,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24390322/

相关文章:

java - Maven 存储库位置未在 Eclipse 中更新

java - 如何增加线宽(Java Applet)

node.js - Mongodb有条件更新双重嵌套数组

javascript - Nodejs 在每个请求中连接数据库

spring - Spring Boot 中的 Dispatcher Servlet

mongodb - 计算符合给定条件的子文档

java - 如何对java中ExecutorService内部的相似线程求和?

java - 将 Spring boot 1.5 迁移到 2.x 无法启动应用程序

java - Hibernate BeanCreationException 异常

java - 使用 Spring Autowiring 时创建 bean