【问题标题】:MongoCleaner Threads Count goes very highMongoCleaner 线程数非常高
【发布时间】:2026-01-11 12:55:02
【问题描述】:

不知何故,MongoDB 应用程序最终导致大量 MongoCleanerXXX 线程处于“Timed Waiting”状态,最终导致“OutOfMemory - 无法创建新的本机线程”问题。我正在为 MongoClient 和 dataStore 对象创建一个单例对象,并使用 Morphia 进行 CURD 操作。

我正在使用 Playframework、MongoDB-2.6、mongo-java-driver-2.11.2.jar、morphia-0.99.1-SNAPSHOT.jar

以下是创建数据存储对象的代码。

public enum AppMongoConfig {
    INSTANCE;

    private MongoClient mongo;
    private Morphia morphia = new Morphia();;
    private Datastore datastore;
    private String ip;
    private String schema;
    private DB db;
    private int port;

    private AppMongoConfig() {
        initialize();
    }

    public void initialize() {
        Logger.info(" ##### Initializing mongo app db ######");
        this.ip = Play.application().configuration()
                .getString("appMongoDBHost");
        this.schema = Play.application().configuration()
                .getString("appMongoDBSchema");
        this.port = Play.application().configuration().getInt("appMongoDBPort");
        try {
            this.mongo = new MongoClient(this.ip, this.port);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        this.db = this.mongo.getDB(this.schema);
        this.datastore = this.morphia.createDatastore(this.mongo,
                this.db.getName());
        Logger.info(" ##### Initialized mongo app db ######");
    }

    public Datastore getDs() {
        return this.datastore;
    }
}

这就是我访问数据库的方式

AppMongoConfig.INSTANCE.getDs()
            .find(FileUploadStatusInfo.class).field("pollingId")
            .equal(pollingId).get();

我为我的 java 进程使用线程转储来监视线程,我的线程数不断增加,有时会达到 20K。在 20K 中,几乎 19950 个线程是“MongoCleaner”线程。以下是我在 threaddump 中看到的内容。

    "MongoCleaner1202732389" daemon prio=10 tid=0x00007f360418a000 nid=0x17c6 waiting on condition [0x00007f35ee2e2000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.mongodb.Mongo$CursorCleanerThread.run(Mongo.java:773)

   Locked ownable synchronizers:
    - None

"MongoCleaner298435004" daemon prio=10 tid=0x00007f36081a4000 nid=0x17c4 waiting on condition [0x00007f35ee3e3000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.mongodb.Mongo$CursorCleanerThread.run(Mongo.java:773)

   Locked ownable synchronizers:
    - None

"MongoCleaner1971787750" daemon prio=10 tid=0x00007f36081a2000 nid=0x17c2 waiting on condition [0x00007f35ee4e4000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
    at java.lang.Thread.sleep(Native Method)
    at com.mongodb.Mongo$CursorCleanerThread.run(Mongo.java:773)

   Locked ownable synchronizers:
    - None

这可能是什么原因,作为 MongoDB 的客户端应用程序,我是否做错了什么?

这个问题依然存在,有没有人发现并回答呢。

【问题讨论】:

  • 不是一个解决方案,但您是否考虑过升级 Morphia?您的版本很古老(我猜是 3 或 4 年)。不确定调试它是否有意义。
  • 是的,我已尝试将其更新为 .102 ,但结果相同。

标签: java mongodb playframework morphia


【解决方案1】:

INSTANCE 是来自 EnumJ 吗?也许这就是为什么AppMongoConfig 的设置对我来说有点不寻常的原因。

无论您在做什么,MongoClient 都应该是静态的。您的问题听起来像是您正在创建多个/太多实例。另见MongoDB - massive amount of MongoCleaner threads

【讨论】:

  • INSTANCE 与 public static final MySingleton INSTANCE = new MySingleton(); 相同我使用枚举来实现单例对象,所以我的 mongoClient & dataStore 是一个单例对象。抱歉回复晚了,我几天没上班了。