寻求值为复杂对象的Map深拷贝替代方案(原Gson存内存问题)
Map深拷贝的Gson替代方案(解决内存泄漏问题)
问题背景
- 此前使用Gson实现Map深拷贝,能保证修改拷贝后的Map不会影响原Map,但出现线程持有问题:堆转储中存在大量Gson相关条目,内存持续增长,最终导致请求被拒。
- 尝试过
orgMap.clone()、new HashMap<>(orgMap)、copymap.putAll(orgMap)这些浅拷贝方式,均无法对Map的value对象实现深拷贝——修改拷贝Map中的value会同时影响原Map和拷贝后的Map。
堆转储线程调用栈
Processing Thread 13running , holding [ at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:593) at com.google.gson.stream.JsonReader.peek(JsonReader.java:433) at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:244) at com.google.gson.internal.bind.TypeAdapters$7.read(TypeAdapters.java:241) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:433) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:393) at com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:1367) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:433) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:393) at com.google.gson.Gson$FutureTypeAdapter.read(Gson.java:1367) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.readIntoField(ReflectiveTypeAdapterFactory.java:212) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$FieldReflectionAdapter.readField(ReflectiveTypeAdapterFactory.java:433) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:393) at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:144) at com.google.gson.Gson.fromJson(Gson.java:1227) at com.google.gson.Gson.fromJson(Gson.java:1137) at com.google.gson.Gson.fromJson(Gson.java:1047) at com.google.gson.Gson.fromJson(Gson.java:1014) at com.util.getDeepCopyOfMap(Utils.java:2398) at com.util.ParameterPopulation.applyFiltering(ParameterPopulation.java:800) at com.util.ParameterPopulation.populateSchemaParameters(ParameterPopulation.java:506) at com.util.ParameterPopulation.formAvroRequestBasedOnSession(ParameterPopulation.java:440) at com.util.ParameterPopulation.populateLocationRelatedParameters(ParameterPopulation.java:1343) at com.util.ParameterPopulation.localProcess(ParameterPopulation.java:294) at com.util.AbstractProcessingActivity.process(AbstractProcessingActivity.java:30) at com.util.TransactionImpl.run(TransactionImpl.java:415) at com.util.TransactionHandlerImpl$FaultTolerantTransaction.run(TransactionHandlerImpl.java:466) at java.util.concurrent.ThreadPoolExecutor.runWorker(java.base@11.0.20/ThreadPoolExecutor.java:1128) at java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base@11.0.20/ThreadPoolExecutor.java:628) at java.lang.Thread.run(java.base@11.0.20/Thread.java:829)
可行替代方案
1. 手动实现深拷贝
针对Map中Value的具体类型,编写自定义拷贝逻辑,精准控制每个Value的深拷贝:
public static <K, V> Map<K, V> deepCopyMap(Map<K, V> original, Function<V, V> valueCopier) { Map<K, V> copiedMap = new HashMap<>(); for (Map.Entry<K, V> entry : original.entrySet()) { copiedMap.put(entry.getKey(), valueCopier.apply(entry.getValue())); } return copiedMap; }
示例:若Value为自定义User对象,可传入user -> new User(user.getId(), user.getName(), user.getAddress().clone())作为拷贝函数,确保嵌套对象也被深拷贝。
2. 使用Apache Commons Lang的SerializationUtils
通过序列化实现通用深拷贝,要求Map的Key和Value均实现Serializable接口:
import org.apache.commons.lang3.SerializationUtils; public static <K, V> Map<K, V> deepCopyMap(Map<K, V> original) { return SerializationUtils.clone(original); }
注意:该方式性能略低,且不支持不可序列化的类型。
3. 基于Jackson实现深拷贝
与Gson逻辑类似,但Jackson的线程安全性更优,内存泄漏风险更低:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.core.type.TypeReference; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); public static <K, V> Map<K, V> deepCopyMap(Map<K, V> original) throws IOException { String json = OBJECT_MAPPER.writeValueAsString(original); return OBJECT_MAPPER.readValue(json, new TypeReference<Map<K, V>>() {}); }
建议使用单例ObjectMapper实例,避免重复创建带来的性能开销。
4. 模型类实现Cloneable接口
若Value为自定义模型类,让类实现Cloneable并重写clone()方法,实现自身的深拷贝逻辑:
public class User implements Cloneable { private String id; private String name; private Address address; // 嵌套对象需同样实现Cloneable @Override protected Object clone() throws CloneNotSupportedException { User cloned = (User) super.clone(); cloned.address = (Address) address.clone(); // 深拷贝嵌套对象 return cloned; } }
拷贝Map时遍历每个Entry,调用Value的clone()方法放入新Map即可。
内容的提问来源于stack exchange,提问作者Ganesh ram
相关产品推荐
相关产品推荐

