Version
hibernate-5.6.10
question
After the application runs for a period of time, insufficient heap space and memory overflow occur.
According to the memory snapshot, a large number of org.hibernate.engine.query.spi.QueryPlanCache objects can be seen
reason
QueryPlanCache will cache sql so that the same sql can be compiled repeatedly.
If a large number of in queries are used, due to the different number of parameters, hibernate will cache them as different sql, thus caching a large number of sql and causing heap memory overflow.
solve
Add configuration parameters to limit the number of sql cached
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的幂
Note
The in_clause_parameter_padding parameter allows the number of parameters in the in query condition to be automatically filled to the power of 2 to reduce the number of different SQL. For example,
1 or 2 parameters are automatically constructed as 'in (?,?)', and 3 and 4 parameters are constructed as 'in (?,?,?,?)'.
For populated bind parameters, the last parameter value provided will be used
Avoid using this parameter in the following situations:
- If the execution plan is not cached, this parameter will not have the effect of reducing the cache, but will reduce the query efficiency because of the additional binding parameters.
- If the IN query contains a large number of elements, parameter padding can greatly increase the number of parameters in the IN clause. For example, a list with 129 elements will be filled to 256 parameters.
source code
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 );
}
}