版本

hibernate-5.6.10

问题

应用运行一段时间后发生堆空间不足内存溢出 根据内存快照可见大量org.hibernate.engine.query.spi.QueryPlanCache对象

原因

QueryPlanCache会缓存sql,以便于相同的sql重复编译 如果大量使用in查询,由于参数数量不同,hibernate会把其当成不同的sql进行缓存,从而缓存大量的sql导致heap内存溢出。

解决

添加配置参数限制缓存的sql数量

spring:

jpa:

hibernate:

properties:

hibernate:

query:

plan_cache_max_size: 64 #缓存大小,默认值2048

plan_parameter_metadata_max_size: 32 #参数元数据大小,默认值128

in_clause_parameter_padding: true #对于in查询生成sql语句参数数量使用2的幂

in_clause_parameter_padding参数让in查询条件的参数数量自动填充到2的幂以减少不同sql的数量 例如,1或2个参数则自动构建为 ‘in (?,?)’ 3,4个参数构建为 ‘in (?,?,?,?)’。 对于填充的绑定参数,将使用提供的最后一个参数值

以下情况避免使用此参数:

如果不缓存执行计划,此参数起不到减少缓存的效果,反而因为额外的绑定参数降低了查询效率。如果in查询包含大量元素,参数填充可能会大大增加 IN 子句中的参数数量。例如,包含 129 个元素的列表将填充到 256 个参数。

源码

org.hibernate:hibernate-core org.hibernate.engine.query.spi.QueryPlanCache

/**

* Acts as a cache for compiled query plans, as well as query-parameter metadata.

*

* @see Environment#QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE

* @see Environment#QUERY_PLAN_CACHE_MAX_SIZE

*

* @author Steve Ebersole

*/

public class QueryPlanCache implements Serializable {

/**

* The default strong reference count.

*/

public static final int DEFAULT_PARAMETER_METADATA_MAX_COUNT = 128;

/**

* The default soft reference count.

*/

public static final int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;

public QueryPlanCache(final SessionFactoryImplementor factory, QueryPlanCreator queryPlanCreator) {

this.factory = factory;

this.queryPlanCreator = queryPlanCreator;

Integer maxParameterMetadataCount = ConfigurationHelper.getInteger(

Environment.QUERY_PLAN_CACHE_PARAMETER_METADATA_MAX_SIZE,

factory.getProperties()

);

if ( maxParameterMetadataCount == null ) {

maxParameterMetadataCount = ConfigurationHelper.getInt(

Environment.QUERY_PLAN_CACHE_MAX_STRONG_REFERENCES,

factory.getProperties(),

DEFAULT_PARAMETER_METADATA_MAX_COUNT

);

}

Integer maxQueryPlanCount = ConfigurationHelper.getInteger(

Environment.QUERY_PLAN_CACHE_MAX_SIZE,

factory.getProperties()

);

if ( maxQueryPlanCount == null ) {

maxQueryPlanCount = ConfigurationHelper.getInt(

Environment.QUERY_PLAN_CACHE_MAX_SOFT_REFERENCES,

factory.getProperties(),

DEFAULT_QUERY_PLAN_MAX_COUNT

);

}

queryPlanCache = new BoundedConcurrentHashMap( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );

parameterMetadataCache = new BoundedConcurrentHashMap<>(

maxParameterMetadataCount,

20,

BoundedConcurrentHashMap.Eviction.LIRS

);

nativeQueryInterpreter = factory.getServiceRegistry().getService( NativeQueryInterpreter.class );

}

}

文章链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: