Spring jpa/hibernate query cache leads to memory overflow

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
insert image description here

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:

  1. 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.
  2. 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 );
	}
}

Guess you like

Origin blog.csdn.net/zhoudingding/article/details/130819658