java perm 区_记一次PERM区内存泄漏

现象

生产上Perm配置了400M,发生了java.lang.OutOfMemoryError: PermGen space。然调整了600M,没过过久,还是OOM了。

分析过程

增加启动参数 -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的库,从输出日志来看,在做对象属性拷贝的时候会动态的生成并加载mapper类。来瞅瞅源码去

public Mapper 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处可以看出,在做对象属性考被的时候,会动态生成Mapper类,并进行缓存。

那问题来了?不是有缓存的吗,怎么还在刷屏呢?移步看下隔壁小王写的业务代码。

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缓存。不断的创建factory,不断的动态创建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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值