[英]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.