简体   繁体   English

Memory 泄漏与 Mongo Java 连接

[英]Memory leak with Mongo Java Connection

I am constructing MongoClient Connection in the below manner:我正在以下列方式构建 MongoClient 连接:

public static synchronized MongoClient getInstance(String mongoDbUri) {
        try {
            // Standard URI format: mongodb://[dbuser:dbpassword@]host:port/dbname
            if( mongoClient == null ){
                mongoClient = new MongoClient(
                              new MongoClientURI(mongoDbUri));
            }
        } catch (Exception e) {
            log.error(
                    "Error mongo connection : ",
                    e.getCause());
        }
        return mongoClient;
    }
  

        

Over a period of time when multiple transaction is run I am seeing some memory eat up with the application which is not getting released.在运行多个事务的一段时间内,我看到一些 memory 吞噬了未发布的应用程序。

When analysed the heap dump saw that there was memory consumption was maximum with the class分析堆转储时,发现 memory 消耗最大,class

com.mongodb.internal.connection.PowerOfTwoBufferPool

The mongo client is trying to connect to a mongos instance.The application has 3 replica sets on 3 shards and one config server to hold the metadata. mongo 客户端正在尝试连接到一个 mongos 实例。该应用程序在 3 个分片上有 3 个副本集和一个用于保存元数据的配置服务器。

To add more details to the same, I have a spring managed bean annotated with @Component .There is an annotation with @PostConstruct for the bean in which the above method is called.In the spring class we are doing insert/update/create using the Mongo Client.为了添加更多详细信息,我有一个 spring 托管 bean 用@Component注释。对于调用上述方法的 bean 有一个带有@PostConstruct的注释。在 spring ZA2F2ED4F8EBC2/createCBB4DC 中,我们正在使用insert/update/create update401创建CBB4DC2 Mongo 客户端。

Thanks.谢谢。

The PowerOfTwoBufferPool is actually a is a cache, so this may look like a memory leak at the first look. PowerOfTwoBufferPool实际上是一个缓存,所以乍一看这可能看起来像内存泄漏。

See the linked reply for details:详情见链接回复

... this behaviour is expected since PowerOfTwoBufferPool is a cache. ...这种行为是预期的,因为 PowerOfTwoBufferPool 是一个缓存。 Hence it may look like a leak.因此它可能看起来像泄漏。

In short, the PowerOfTwoBufferPool holds a number of pools of ByteBuffer instances, each pool containing a set of equal-sized buffers.简而言之,PowerOfTwoBufferPool 包含多个 ByteBuffer 实例池,每个池包含一组相同大小的缓冲区。 The smallest size is 1K, and the largest is 16MB, incrementing in power of two sizes from 1K to 16MB.最小的大小为 1K,最大的为 16MB,从 1K 到 16MB 的两个大小的幂递增。 The size of each pool of equal-sized buffers is not limited, and is determined by application usage.每个大小相等的缓冲区池的大小不受限制,由应用程序使用情况决定。 Once a buffer is cached in a pool, it remains pooled (or in-use) until the MongoClient is closed.一旦缓冲区缓存在池中,它就会保持池化(或使用中),直到 MongoClient 关闭。 As a result, it's totally expected that during introspection of JVM state, the contents of the pools would show as a leak suspect, just as any cache would.因此,完全可以预期在自省 JVM 状态期间,池的内容将显示为泄漏嫌疑人,就像任何缓存一样。

The PowerOfTwoBufferPool exists in order to reduce GC load. PowerOfTwoBufferPool 的存在是为了减少 GC 负载。 It's fairly well known that modern garbage collectors in the JVM treat large allocations differently from smaller ones, so if an application were to not do any pooling of large objects (like these buffers) it will have the effect of increasing GC load, because the garbage collector has to do more work collecting these large objects than it does smaller ones.众所周知,JVM 中的现代垃圾收集器处理大分配与较小分配的方式不同,因此如果应用程序不对大对象(如这些缓冲区)进行任何池化,它将具有增加 GC 负载的效果,因为垃圾收集这些大对象比收集小对象需要做更多的工作。 The cost of this is that the driver holds on to memory that could be used by other parts of the application.这样做的代价是驱动程序保留了可供应用程序其他部分使用的内存。 In particular, it holds on to enough memory to handle the largest peak load seen so far by the application.特别是,它拥有足够的内存来处理应用程序迄今为止看到的最大峰值负载。

Add a PreDestroy method where you close your client:在关闭客户端的位置添加 PreDestroy 方法:

@PreDestroy
public void preDestroy() {
    try {
       if (mongoClient != null ) {
          mongoClient.close();
       }
    } catch (Exception e) {
        log.error("Error closing mongo connection : ",
                e.getCause());
    }
}

Of course mongoClient must be accessible to the preDestroy() method当然 mongoClient 必须可以被 preDestroy() 方法访问

The MongoDB driver shouldn't be part of a pool as it is unnecessary. MongoDB 驱动程序不应该是池的一部分,因为它是不必要的。 Instead when I'm running unit tests and I don't want multiple MongoClients I use a static method.相反,当我运行单元测试并且我不想要多个 MongoClients 时,我使用 static 方法。 In Kotlin it looks like this:在 Kotlin 中,它看起来像这样:

import com.mongodb.MongoClientSettings
import com.mongodb.reactivestreams.client.*
import org.bson.codecs.configuration.CodecRegistries
import org.bson.codecs.configuration.CodecRegistry
import org.bson.codecs.pojo.PojoCodecProvider

object MfeDatabase {
    init {
        println("SINGLETON CREATED")
    }
   const val DATABASE =""



     val client: MongoClient = MongoClients.create()
    private val pojoCodecRegistry: CodecRegistry = CodecRegistries.fromRegistries(
        MongoClientSettings.getDefaultCodecRegistry(),
        CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build())
    )
    private val db: MongoDatabase =
        client.getDatabase(DATABASE).withCodecRegistry(pojoCodecRegistry)


    @JvmStatic
    fun getDatabase(): MongoDatabase {
        return db
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM