java - jdbc4connection + boneCP + MAT的内存泄漏

标签 java mysql spring-mvc jpa spring-jdbc

我正在为我的 Web 服务应用程序使用 Spring + JPA,但是为了实现一些巨大的查询,我实现了一个单独的服务,该服务从 spring DataSourceUtil(org.springframework.jdbc.datasource.DataSourceUtils) 获取连接并在操作之后它释放连接。但是我面临堆内存不足的问题。因此,我在发生 outOfMemory 错误之前进行了几次堆转储,并使用 MAT 对其进行了分析,每次我都怀疑有相同的泄漏。

70 个“com.mysql.jdbc.JDBC4Connection”实例,由“org.apache.catalina.loader.WebappClassLoader @ 0x71bc20d20”加载,占用 2,079,740,488 (88.56%) 字节。

最大的实例:

•com.mysql.jdbc.JDBC4Connection @ 0x71d6d8400 - 52,762,088 (2.25%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d7042e0 - 52,574,048 (2.24%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d786248 - 52,070,176 (2.22%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d6c4070 - 51,949,880 (2.21%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d719118 - 51,860,584 (2.21%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d6ef270 - 51,782,800 (2.21%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d773ba8 - 51,389,608 (2.19%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d75f6c0 - 51,380,112 (2.19%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d749998 - 51,132,832 (2.18%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d731880 - 50,915,200 (2.17%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d8911e0 - 41,942,816 (1.79%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d7ed2e0 - 38,396,256 (1.64%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d8e2bc0 - 37,801,216 (1.61%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d82f3e8 - 36,354,288 (1.55%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730e82790 - 36,069,024 (1.54%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d7b51b8 - 36,045,040 (1.53%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d7daff0 - 35,994,880 (1.53%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d86f708 - 35,956,024 (1.53%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d815ea8 - 35,486,624 (1.51%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d84d5a0 - 35,382,672 (1.51%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d7ff978 - 35,377,072 (1.51%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d7c7068 - 34,493,840 (1.47%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d930420 - 34,492,640 (1.47%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d84b790 - 34,413,488 (1.47%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d871818 - 34,278,272 (1.46%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d899138 - 34,246,296 (1.46%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d906c08 - 34,176,552 (1.46%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d8bd058 - 34,006,576 (1.45%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d94e820 - 33,817,904 (1.44%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d8b9500 - 33,746,960 (1.44%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d967730 - 33,529,088 (1.43%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730eacbc0 - 31,724,256 (1.35%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730f0f958 - 28,824,064 (1.23%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730eba550 - 28,616,040 (1.22%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730f0d560 - 28,584,872 (1.22%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730eaafa0 - 28,402,216 (1.21%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730e86310 - 28,361,144 (1.21%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d97b5a0 - 28,310,904 (1.21%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730ea6300 - 28,057,256 (1.19%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730ee7d18 - 27,558,360 (1.17%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x730eec528 - 27,307,648 (1.16%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d9bbce0 - 26,258,176 (1.12%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d8e0c48 - 24,571,352 (1.05%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d9a7668 - 24,250,896 (1.03%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d904dc8 - 24,054,744 (1.02%) bytes. 
•com.mysql.jdbc.JDBC4Connection @ 0x71d692430 - 23,683,744 (1.01%) bytes. 

我的代码在服务层实现以操作大量查询

import org.springframework.jdbc.datasource.DataSourceUtils;

@Autowired
javax.sql.DataSource dataSource;


@Override
public List<Dto> getDto(String name) {
    StringBuilder queryBuilder = new StringBuilder("Query to execute");
    final String query = queryBuilder.toString();
    queryBuilder = null;
    Connection connection = null;
    List<Dto> dtos = new ArrayList<Dto>();
    try{
        connection = DataSourceUtils.getConnection(dataSource);
        if(connection!=null){
            PreparedStatement preparedStatement = connection.prepareStatement(query);
            long time1= System.currentTimeMillis();
            ResultSet rs = preparedStatement.executeQuery(query);

            while(rs.next()) {
                Dto dto = new Dto();
                dto.setId(rs.getLong("id"));
                dto.setDetail(rs.getString("detail"));
                dto.setTitle(rs.getString("cardName"));
                dto.setValue(rs.getString("askValue"));
                dtos.add(dto);
            }
            LOGGER.info("Time in inserting getTarrotDto : {} ms", (System.currentTimeMillis() - time1));
        }
    } catch (Exception e) {
        LOGGER.error("Error occured while inserting from CustomDataBaseService "+e);
        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }finally {
        if(queryBuilder != null){
            queryBuilder = null;
        } 
        DataSourceUtils.releaseConnection(connection,dataSource);
    }
    return dtos;
}

我的 PersistenceConfig 是

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.jolbox.bonecp.BoneCPDataSource;

public class PersistenceConfig {

    @Autowired
    private Environment environment;

    @Bean
    public DataSource dataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();

        dataSource.setDriverClass(environment.getRequiredProperty(PROPERTY_NAME_JDBC_DRIVER_CLASSNAME));
        dataSource.setJdbcUrl(environment.getRequiredProperty(PROPERTY_NAME_JDBC_URL));
        dataSource.setUsername(environment.getRequiredProperty(PROPERTY_NAME_JDBC_USERNAME));
        dataSource.setPassword(environment.getRequiredProperty(PROPERTY_NAME_JDBC_PASSWORD));
        dataSource.setPartitionCount(4);
        dataSource.setMinConnectionsPerPartition(10);
        dataSource.setMaxConnectionsPerPartition(20);
        dataSource.setAcquireIncrement(10);
        dataSource.setStatementsCacheSize(200);

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        final LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

        factoryBean.setDataSource(dataSource());
        factoryBean.setPersistenceUnitName(PROPERTY_NAME_RH_ETT_DOMAIN);
        factoryBean.setJpaVendorAdapter(hibernateJpaVendorAdapter());
        factoryBean.setJpaDialect(hibernateJpaDialect());
        factoryBean.setJpaPropertyMap(jpaPropertyMap());
        return factoryBean;
    }

    @Bean(name = "transactionManager")
    public JpaTransactionManager transactionManager() {
        final JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();

        jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        jpaTransactionManager.setDataSource(dataSource());

        return jpaTransactionManager;
    }

    @Bean
    public HibernateJpaDialect hibernateJpaDialect() {
        return new HibernateJpaDialect();
    }

    @Bean
    public HibernateJpaVendorAdapter hibernateJpaVendorAdapter() {
        final HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setShowSql(Boolean.parseBoolean(environment.getProperty(PROPERTY_NAME_JDBC_SHOW_SQL)));
        jpaVendorAdapter.setGenerateDdl(Boolean.parseBoolean(environment.getProperty(PROPERTY_NAME_JDBC_GENERATE_DDL)));
        jpaVendorAdapter.setDatabase(Database.valueOf(environment.getProperty(PROPERTY_NAME_JDBC_DATABASE)));
        String databasePlatform = environment.getProperty(PROPERTY_NAME_JDBC_DATABASE_PLATFORM);
        if (databasePlatform != null) {
            jpaVendorAdapter.setDatabasePlatform(environment.getProperty(PROPERTY_NAME_JDBC_DATABASE_PLATFORM1));
        }

        return jpaVendorAdapter;
    }

    @Bean(name = "jpaPropertyMap")
    public Map<String, Object> jpaPropertyMap() {
        Map<String, Object> map = new HashMap<>();
        map.put("hibernate.jdbc.batch_size", Integer.parseInt(environment.getProperty(PROPERTY_NAME_HIBERNATE_JDBC_BATCH_SIZE)));
        return map;
    }
}

请帮帮我,谢谢。

最佳答案

你没有关闭你的结果集(并且 BoneCP 也被弃用,迁移到 HikariCP)

关于java - jdbc4connection + boneCP + MAT的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40779862/

相关文章:

mysql - SQL:将多行插入具有静态值的表中

java - Spring MVC uri 与百分比编码字符的映射

javascript - 自动生成网站图表

java - 有效使用 JavaOptional.ofNullable

Java split方法无法正常工作?

java - 推土机映射内部类

php - 如何将 url 保存到列表或数据库中?

mysql - 无法触发运行

java - 通过 Android Activity 类访问创建变量

java - spring mvc ajax数据用Jackson截断