DATACMNS-1101 - Use construction object array pooling.
Use a thread-local object pool for constructor arguments to reduce object allocations.
This commit is contained in:
committed by
Oliver Gierke
parent
e6e3290e59
commit
17b82cfe37
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.convert;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -39,6 +40,19 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private final int ARG_CACHE_SIZE = 100;
|
||||
|
||||
private final ThreadLocal<Object[][]> objectPool = ThreadLocal.withInitial(() -> {
|
||||
|
||||
Object[][] cached = new Object[ARG_CACHE_SIZE][];
|
||||
|
||||
for (int i = 0; i < ARG_CACHE_SIZE; i++) {
|
||||
cached[i] = new Object[i];
|
||||
}
|
||||
|
||||
return cached;
|
||||
});
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T, E extends PersistentEntity<? extends T, P>, P extends PersistentProperty<P>> T createInstance(E entity,
|
||||
ParameterValueProvider<P> provider) {
|
||||
@@ -64,8 +78,9 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
throw new MappingInstantiationException(entity, Collections.emptyList(), e);
|
||||
}
|
||||
}
|
||||
int parameterCount = constructor.getConstructor().getParameterCount();
|
||||
|
||||
Object[] params = new Object[constructor.getConstructor().getParameterCount()];
|
||||
Object[] params = parameterCount < ARG_CACHE_SIZE ? objectPool.get()[parameterCount] : new Object[parameterCount];
|
||||
int i = 0;
|
||||
for (Parameter<?, P> parameter : constructor.getParameters()) {
|
||||
params[i++] = provider.getParameterValue(parameter);
|
||||
@@ -74,7 +89,9 @@ public enum ReflectionEntityInstantiator implements EntityInstantiator {
|
||||
try {
|
||||
return BeanUtils.instantiateClass(constructor.getConstructor(), params);
|
||||
} catch (BeanInstantiationException e) {
|
||||
throw new MappingInstantiationException(entity, Arrays.asList(params), e);
|
||||
throw new MappingInstantiationException(entity, new ArrayList<>(Arrays.asList(params)), e);
|
||||
} finally {
|
||||
Arrays.fill(params, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +66,12 @@ import org.springframework.util.ReflectionUtils;
|
||||
*/
|
||||
public class ClassGeneratingPropertyAccessorFactory implements PersistentPropertyAccessorFactory {
|
||||
|
||||
// Pooling of parameter arrays to prevent excessive object allocation.
|
||||
private final ThreadLocal<Object[]> argumentCache = ThreadLocal.withInitial(() -> new Object[1]);
|
||||
|
||||
private volatile Map<PersistentEntity<?, ?>, Constructor<?>> constructorMap = new HashMap<>(32);
|
||||
private volatile Map<TypeInformation<?>, Class<PersistentPropertyAccessor>> propertyAccessorClasses = new HashMap<>(
|
||||
32);
|
||||
private volatile Map<Class<PersistentPropertyAccessor>, Constructor<?>> constructorMap = new HashMap<>(32);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -77,15 +80,28 @@ public class ClassGeneratingPropertyAccessorFactory implements PersistentPropert
|
||||
@Override
|
||||
public PersistentPropertyAccessor getPropertyAccessor(PersistentEntity<?, ?> entity, Object bean) {
|
||||
|
||||
final Class<PersistentPropertyAccessor> propertyAccessorClass = propertyAccessorClasses.computeIfAbsent(
|
||||
entity.getTypeInformation(), k -> potentiallyCreateAndRegisterPersistentPropertyAccessorClass(entity));
|
||||
Constructor<?> constructor = constructorMap.get(entity);
|
||||
|
||||
if (constructor == null) {
|
||||
|
||||
Class<PersistentPropertyAccessor> accessorClass = potentiallyCreateAndRegisterPersistentPropertyAccessorClass(
|
||||
entity);
|
||||
constructor = accessorClass.getConstructors()[0];
|
||||
|
||||
Map<PersistentEntity<?, ?>, Constructor<?>> constructorMap = new HashMap<>(this.constructorMap);
|
||||
constructorMap.put(entity, constructor);
|
||||
this.constructorMap = constructorMap;
|
||||
}
|
||||
|
||||
Object[] args = argumentCache.get();
|
||||
args[0] = bean;
|
||||
|
||||
try {
|
||||
|
||||
return (PersistentPropertyAccessor) constructorMap
|
||||
.computeIfAbsent(propertyAccessorClass, k -> propertyAccessorClass.getConstructors()[0]).newInstance(bean);
|
||||
return (PersistentPropertyAccessor) constructor.newInstance(args);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(String.format("Cannot create persistent property accessor for %s", entity), e);
|
||||
} finally {
|
||||
args[0] = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user