美文网首页JAVA
记一次PERM区内存泄漏

记一次PERM区内存泄漏

作者: HelloArmin | 来源:发表于2016-09-23 13:19 被阅读503次

现象

生产上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<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处可以看出,在做对象属性考被的时候,会动态生成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。

相关文章

  • 记一次PERM区内存泄漏

    现象 生产上Perm配置了400M,发生了java.lang.OutOfMemoryError: PermGen ...

  • Android性能优化-内存泄漏的8个Case

    1. 什么是内存泄漏? JVM内存管理 关于内存泄漏我们要知道,JVM内存分配的几种策略。 静态的 静态的存储区,...

  • 内存泄漏和内存溢出的区别与解决方式

    内存泄漏(memory leak ) 是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄漏,一次内存泄漏...

  • iOS笔记-记录一次内存泄漏发现过程

    iOS笔记-记录一次内存泄漏发现过程 iOS笔记-记录一次内存泄漏发现过程

  • Android LeakCanary 检测内存泄露

    内存泄漏: 指程序在申请内存后 ,无法释放已经申请的内存空间,一次内存泄漏可以忽略,但内存泄漏堆积后果很严重,无论...

  • 2-JVM内存结构

    内存结构 方法区 JDK1.7 之前包含1.7 将方法区称为 Perm Space 永久代JDK1.8之后包含1....

  • 内存泄漏

    一、java内存泄漏基础知识 1.java内存的分配策略 (1)静态存储区 方法区 (2)栈区 (3)堆区 ne...

  • 内存泄漏和内存溢出

    内存泄漏:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏似乎不会有大的影响,但内存泄漏堆积后的后果就...

  • 【Android测试】内存泄漏检测 LeakCanary

    什么是内存泄漏和内存溢出?内存泄漏有什么危害?LeakCanary检测内存泄漏? 内存泄漏(Memory Leak...

  • 记一次内存泄漏

    这次c++底层的内存泄漏怎么说呢,让你了解了更多指针内存的东西,说更多了解,反而发现有更多的不了解了,比如指针和整...

网友评论

  • 李程鹏:把MapperFactory弄成静态变量似乎也可以解决溢出问题,我试了一下,没有报错了。代码:
    package core.util;

    import ma.glasnost.orika.MapperFacade;
    import ma.glasnost.orika.MapperFactory;
    import ma.glasnost.orika.impl.DefaultMapperFactory;

    /**
    * Orika对象映射拷贝工具类.
    *
    * @Author 李程鹏
    */
    public class OrikaUtils {
    private static MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    private static MapperFacade mapperFacade = mapperFactory.getMapperFacade();

    /**
    * <strong>Description:</strong>
    * <pre>
    * 映射拷贝对象.
    * </pre>
    *
    * @param origin 原对象
    * @param targetClass 目标对象的Class
    * @Return {@code T} - 映射结果
    */
    public static <T> T map(Object origin, Class<T> targetClass) {
    // MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
    // MapperFacade mapperFacade = mapperFactory.getMapperFacade();
    return mapperFacade.map(origin, targetClass);
    }
    }

本文标题:记一次PERM区内存泄漏

本文链接:https://www.haomeiwen.com/subject/ozyzettx.html