簡體   English   中英

Memory 泄漏與 Mongo Java 連接

[英]Memory leak with Mongo Java Connection

我正在以下列方式構建 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;
    }
  

        

在運行多個事務的一段時間內,我看到一些 memory 吞噬了未發布的應用程序。

分析堆轉儲時,發現 memory 消耗最大,class

com.mongodb.internal.connection.PowerOfTwoBufferPool

mongo 客戶端正在嘗試連接到一個 mongos 實例。該應用程序在 3 個分片上有 3 個副本集和一個用於保存元數據的配置服務器。

為了添加更多詳細信息,我有一個 spring 托管 bean 用@Component注釋。對於調用上述方法的 bean 有一個帶有@PostConstruct的注釋。在 spring ZA2F2ED4F8EBC2/createCBB4DC 中,我們正在使用insert/update/create update401創建CBB4DC2 Mongo 客戶端。

謝謝。

PowerOfTwoBufferPool實際上是一個緩存,所以乍一看這可能看起來像內存泄漏。

詳情見鏈接回復

...這種行為是預期的,因為 PowerOfTwoBufferPool 是一個緩存。 因此它可能看起來像泄漏。

簡而言之,PowerOfTwoBufferPool 包含多個 ByteBuffer 實例池,每個池包含一組相同大小的緩沖區。 最小的大小為 1K,最大的為 16MB,從 1K 到 16MB 的兩個大小的冪遞增。 每個大小相等的緩沖區池的大小不受限制,由應用程序使用情況決定。 一旦緩沖區緩存在池中,它就會保持池化(或使用中),直到 MongoClient 關閉。 因此,完全可以預期在自省 JVM 狀態期間,池的內容將顯示為泄漏嫌疑人,就像任何緩存一樣。

PowerOfTwoBufferPool 的存在是為了減少 GC 負載。 眾所周知,JVM 中的現代垃圾收集器處理大分配與較小分配的方式不同,因此如果應用程序不對大對象(如這些緩沖區)進行任何池化,它將具有增加 GC 負載的效果,因為垃圾收集這些大對象比收集小對象需要做更多的工作。 這樣做的代價是驅動程序保留了可供應用程序其他部分使用的內存。 特別是,它擁有足夠的內存來處理應用程序迄今為止看到的最大峰值負載。

在關閉客戶端的位置添加 PreDestroy 方法:

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

當然 mongoClient 必須可以被 preDestroy() 方法訪問

MongoDB 驅動程序不應該是池的一部分,因為它是不必要的。 相反,當我運行單元測試並且我不想要多個 MongoClients 時,我使用 static 方法。 在 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