JDBC 大容量复制中可能存在内存泄漏

Posted

技术标签:

【中文标题】JDBC 大容量复制中可能存在内存泄漏【英文标题】:Possible memory leak in JDBC bulkcopy 【发布时间】:2019-12-01 16:40:23 【问题描述】:

我正在编写一个 Spring Boot 2 应用程序,并且我正在使用 SQL 批量复制功能在 SQL Server 2012 数据库中插入多条记录。 每次我插入 ~700 行时,我都会泄漏 600 MB

我已经尝试过 Microsoft 驱动程序版本 6.4.0.jre8 和 7.2.2.jre8,但一切都发生了变化。 我已经尝试为 tomcat 更改 Hikari 连接池,但结果是一样的。

为了调用 Microsoft API,我使用的是包装框架 (https://github.com/bytefish/JSqlServerBulkInsert),但代码很干净:

 public void saveAll(Connection connection, SQLServerBulkCopyOptions options, Stream<TEntity> entities) 
        // Create a new SQLServerBulkCopy Instance on the given Connection:
        try (SQLServerBulkCopy sqlServerBulkCopy = new SQLServerBulkCopy(connection)) 
             // Set the Options:
            sqlServerBulkCopy.setBulkCopyOptions(options);
            // The Destination Table to write to:
            sqlServerBulkCopy.setDestinationTableName(mapping.getTableDefinition().GetFullQualifiedTableName());
            // The SQL Records to insert:
            ISQLServerBulkRecord record = new SqlServerRecord<TEntity>(mapping.getColumns(), entities.iterator());
            // Finally start the Bulk Copy Process:
            sqlServerBulkCopy.writeToServer(record);
            // Handle Exceptions:
         catch (SQLServerException e) 
            // Wrap it in a RunTimeException to provide a nice API:
            throw new RuntimeException(e);
        
    

当我使用 Eclipse 内存分析器时,我得到了以下结果:

与光:

“com.zaxxer.hikari.pool.PoolEntry”的一个实例由加载 “sun.misc.Launcher$AppClassLoader@0x81611758”占用640.619.616 (95,94 %) 个字节。内存是在一个实例中累积的 “”加载的“java.lang.Object[]”。

关键字 com.zaxxer.hikari.pool.PoolEntry java.lang.Object[] sun.misc.Launcher$AppClassLoader @ 0x81611758 "

使用 Tomcat:

“加载了“org.apache.tomcat.jdbc.pool.ConnectionPool”的一个实例 由“sun.misc.Launcher$AppClassLoader @ 0x81614fa0”占用 640.805.840 (95,92 %) 字节。内存在“”加载的“java.lang.Object[]”的一个实例中累积。

关键字 java.lang.Object[] sun.misc.Launcher$AppClassLoader @ 0x81614fa0 org.apache.tomcat.jdbc.pool.ConnectionPool"

【问题讨论】:

你怎么知道这是泄漏而不是内存尚未被 GC 回收?调用close() 并不能保证立即从内存中删除所有数据。 我在强制 GC 并且 600 MB 的差距没有改变。 Eclipse Memory Analyzer 也将其检测为可能的泄漏 【参考方案1】:

不是司机。我在方法中使用了一个列表,并希望在方法范围之后被收集。我将引用分配给 null(之前我清除了集合),GC 可以收集它。

【讨论】:

以上是关于JDBC 大容量复制中可能存在内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

什么调试器可以检查 C++ 代码是不是存在内存泄漏? [复制]

Tomcat如何检测内存泄漏

tomcat7 - jdbc 数据源 - 这很可能会造成内存泄漏

你的程序中可能存在内存泄漏(收藏!)

字符串内存分配中可能存在内存泄漏

独立的 jdbc-pool 实现内存泄漏