現(xiàn)象
生產上Perm配置了400M袁稽,發(fā)生了java.lang.OutOfMemoryError: PermGen space
。然調整了600M擒抛,沒過過久推汽,還是OOM了补疑。
分析過程
增加啟動參數(shù) -verbose, 將類加載的日志進行輸出,進行觀察歹撒。
[Loaded ma.glasnost.orika.generated.Orika_OrderBase_CreateOrderReq_Mapper2063753710 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinitionParameter_ServiceDefinitionParameterReq_Mapper458086693 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinition_ServiceDefinitionReq_Mapper925591567 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ActivityDefinition_ActivityDefinitionReq_Mapper8350956 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinition_ServiceDefinitionReq_Mapper786907469 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBase_CreateOrderReq_Mapper1746474167 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ActivityDefinitionDetail_ActivityDefinitionDetail_Mapper140733274 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBase_CreateOrderReq_Mapper924640771 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBaseServiceParameter_OrderBaseServiceParameterReq_Mapper886688266 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinitionParameter_ServiceDefinitionParameterReq_Mapper536925325 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ActivityDefinition_ActivityDefinitionReq_Mapper222008270 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ActivityDefinitionDetail_ActivityDefinitionDetail_Mapper337814190 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBaseServiceParameter_OrderBaseServiceParameterReq_Mapper1104718977 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinitionParameter_ServiceDefinitionParameterReq_Mapper1058897791 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderLine_OrderlineReq_Mapper1088311475 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderLine_OrderlineReq_Mapper1251024503 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_Reference_ReferenceReq_Mapper2103917791 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_Reference_ReferenceReq_Mapper1328332983 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBaseSubscribedServiceEntity_OrderBaseSubscribedServiceEntityReq_Mapper882926156 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBaseSubscribedServiceEntity_OrderBaseSubscribedServiceEntityReq_Mapper1993002189 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBase_CreateOrderReq_Mapper377652581 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinition_ServiceDefinitionReq_Mapper1617967640 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderLine_OrderlineReq_Mapper470033788 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_Reference_ReferenceReq_Mapper1878357978 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderLine_OrderlineReq_Mapper404646422 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBaseSubscribedServiceEntity_OrderBaseSubscribedServiceEntityReq_Mapper1959188152 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_Reference_ReferenceReq_Mapper1509269350 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_OrderBaseSubscribedServiceEntity_OrderBaseSubscribedServiceEntityReq_Mapper1716988231 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ServiceDefinition_ServiceDefinitionReq_Mapper1043329959 from __JVM_DefineClass__]
[Loaded ma.glasnost.orika.generated.Orika_ActivityDefinition_ActivityDefinitionReq_Mapper1062832431 from __JVM_DefineClass__]
被orika的 類加載信息刷屏了莲组。orika是一個bean mapping的庫,從輸出日志來看暖夭,在做對象屬性拷貝的時候會動態(tài)的生成并加載mapper類锹杈。來瞅瞅源碼去
public Mapper<Object, Object> lookupMapper(MapperKey mapperKey) {
Object mapper = this.getRegisteredMapper(mapperKey.getAType(), mapperKey.getBType(), true); // 1
if(mapper == null && this.useAutoMapping) {
synchronized(this) {
try {
if(ClassUtil.isImmutable(mapperKey.getBType()) && !this.objectFactoryRegistry.containsKey(mapperKey.getBType())) {
throw new MappingException("No converter registered for conversion from " + mapperKey.getAType() + " to " + mapperKey.getBType() + ", nor any ObjectFactory which can generate " + mapperKey.getBType() + " from " + mapperKey.getAType());
}
if(LOGGER.isDebugEnabled()) {
LOGGER.debug("No mapper registered for " + mapperKey + ": attempting to generate");
}
ClassMap e = this.classMap(mapperKey.getAType(), mapperKey.getBType()).byDefault(new DefaultFieldMapper[0]).toClassMap();
this.buildObjectFactories(e);
mapper = this.buildMapper(e, true); // 2
this.initializeUsedMappers(e);
} catch (MappingException var5) {
var5.setSourceType(mapperKey.getAType());
var5.setDestinationType(mapperKey.getBType());
throw var5;
}
}
}
return (Mapper)mapper;
}
private GeneratedMapperBase buildMapper(ClassMap<?, ?> classMap, boolean isAutoGenerated) {
this.register(classMap.getAType(), classMap.getBType());
this.register(classMap.getBType(), classMap.getAType());
MapperKey mapperKey = new MapperKey(classMap.getAType(), classMap.getBType());
GeneratedMapperBase mapper = this.mapperGenerator.build(classMap);//3
mapper.setMapperFacade(this.mapperFacade);
mapper.setFromAutoMapping(isAutoGenerated);
if(classMap.getCustomizedMapper() != null) {
Mapper customizedMapper = classMap.getCustomizedMapper();
mapper.setCustomMapper(customizedMapper);
}
this.mappersRegistry.add(mapper);
this.classMapRegistry.put(mapperKey, classMap);
return mapper;
}
在this.mapperGenerator.build(classMap) 中 orika會生成A類型與B類型對象之間拷貝代碼然后進行編譯加載。
從1迈着、2竭望、3處可以看出,在做對象屬性考被的時候裕菠,會動態(tài)生成Mapper類咬清,并進行緩存。
那問題來了奴潘?不是有緩存的嗎旧烧,怎么還在刷屏呢?移步看下隔壁小王寫的業(yè)務代碼画髓。
private OrderBase convert(CreateOrderReq req) {
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();//就是他了
mapperFactory.classMap(CreateOrderReq.class, OrderBase.class).byDefault();
MapperFacade mapper = mapperFactory.getMapperFacade();
OrderBase rst = mapper.map(req, OrderBase.class);
return rst;
}
每次調用convert的時候掘剪,都會new一個新的DefaultMapperFactory(), 每個factory都持有它自己的mapper緩存。不斷的創(chuàng)建factory雀扶,不斷的動態(tài)創(chuàng)建mapper類進行加載杖小。然后就沒有然后了。
生成的Mapper 類是什么鬼愚墓?
package ma.glasnost.orika.generated;
public class Orika_UserVO_User_Mapper133221885 extends ma.glasnost.orika.impl.GeneratedMapperBase {
public void mapAtoB(java.lang.Object a, java.lang.Object b, ma.glasnost.orika.MappingContext mappingContext) {
super.mapAtoB(a, b, mappingContext);
com.xx.entity.security.User source = ((com.xx.entity.security.User) a);
com.xx.vo.security.UserVO destination = ((com.xx.vo.security.UserVO) b);
if (((java.lang.String) source.getPassword()) != null) {
destination.setPassword(((java.lang.String) source.getPassword()));
}
if (((java.lang.String) source.getUserName()) != null) {
destination.setUserName(((java.lang.String) source.getUserName()));
}
if (customMapper != null) {
customMapper.mapAtoB(source, destination, mappingContext);
}
}
public void mapBtoA(java.lang.Object a, java.lang.Object b, ma.glasnost.orika.MappingContext mappingContext) {
super.mapBtoA(a, b, mappingContext);
com.xx.vo.security.UserVO source = ((com.xx.vo.security.UserVO) a);
com.xx.entity.security.User destination = ((com.xx.entity.security.User) b);
if (((java.lang.String) source.getPassword()) != null) {
destination.setPassword(((java.lang.String) source.getPassword()));
}
if (((java.lang.String) source.getUserName()) != null) {
destination.setUserName(((java.lang.String) source.getUserName()));
}
if (customMapper != null) {
customMapper.mapBtoA(source, destination, mappingContext);
}
}
}
解決方案
使用OrikaBeanMapper類來進行拷貝額予权,OrikaBeanMapper 封裝了單例的DefaultMapperFactory。