Aop 方面扫描过多的类和方法缓存会占用内存

Aop 方面扫描过多的类和方法缓存会占用内存,aop,expression,aspectj,spring-aop,pointcut,Aop,Expression,Aspectj,Spring Aop,Pointcut,在我们的应用程序中,我们有几个(实际上很多,大约30个)web服务。每个web服务都驻留在自己的WAR文件中,并有自己的Spring上下文,该上下文在应用程序启动时初始化 我们还有许多注释驱动的方面类,可以应用于web服务类。开始时,poincut表达式如下所示: @Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..))") public void methodsToBeLogg

在我们的应用程序中,我们有几个(实际上很多,大约30个)web服务。每个web服务都驻留在自己的WAR文件中,并有自己的Spring上下文,该上下文在应用程序启动时初始化

我们还有许多注释驱动的方面类,可以应用于web服务类。开始时,poincut表达式如下所示:

@Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..))")
  public void methodsToBeLogged() {
  }
通过配置中的条目在服务上启用AOP

但随着web服务数量的增长,我们开始在服务器上体验到
OutOfMemoryException
s。在做了一些分析和分析之后,内存似乎被AspectJExpressionPointcut类实例保留的缓存占用了

每个实例的缓存大约为5MB。由于我们有3个方面和30个服务,因此90个实例总共拥有450MB的数据

在检查了缓存的内容之后,我们意识到它包含了WAR中存在的所有类的Java反射方法实例,即使这些类不是my.package.service.business包的一部分。将点切割表达式修改为在子句中添加
后:

@Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..)) && 
within(my.package.service.business..*)")
  public void methodsToBeLogged() {
  }
内存使用率再次降至正常水平。所有AspectJExpressionPointcut实例总共占用不到1MB


有人能解释为什么会这样吗?为什么第一个切点表达式是不够的?为什么AspectJExpressionPointcut的缓存不共享?

AspectJExpressionPointcut使用一个缓存(shadowMatchCache),它可以根据切入点表达式加快AOP是否应用于某个方法调用的决策。此缓存可能会消耗大量内存

此外,在提供特定bean的所有方法以查看是否存在切入点表达式匹配之前,Spring首先通过调用AspectJExpressionPointcut.matches(类targetClass)检查bean类是否可能匹配。 此方法委托给AspectJ的PointcutExpressionImpl.couldPossiblyMatch()方法。这将执行快速检查类是否“可能”匹配切入点表达式,或者永远不会“确定”匹配。 根据AspectJ开发人员使用内部切入点的说法,结果是更明确的否定。他们也是

但是,无法共享shadowMatchCache,因为它包含每个切入点表达式的匹配或不匹配结果

但至少可以限制缓存的内容。我还认为,一旦applicationContext启动,Spring可能会通过不保留整个缓存来改进这一点。例如,当一个新bean在启动后动态添加到applicationContext中时,他们可能会丢弃所有不匹配项,代价是重新进行一些匹配

AspectJExpressionPointcut类中另一个可能占用内存的是pointCutParser。该解析器可能在applicationContext中的所有AspectJExpressionPointcuts之间共享。在JIRA罚单上抢夺一点