扫描太多类和方法缓存的方面填充内存

时间:2010-11-04 13:29:37

标签: aop expression aspectj spring-aop pointcut

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

我们还有许多应用于Web服务类的注释驱动的方面类。在开始时,poincut表达看起来像这样:

@Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..))")
  public void methodsToBeLogged() {
  }

通过配置输入启用了AOP服务。

但是当网络服务的数量增加时,我们开始在服务器上体验OutOfMemoryException。在进行一些分析和分析之后,看起来内存由AspectJExpressionPointcut类的实例保存的缓存占用。

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

在检查了缓存的内容之后,我们意识到它包含了WAR中存在的所有类的Java反射方法实例,即使是那些不属于my.package.service.business包的类。修改了切入点表达式以使其具有 within 子句:

@Pointcut("execution(public * my.package.service.business.*BusinessServiceImpl.*(..)) && 
within(my.package.service.business..*)")
  public void methodsToBeLogged() {
  }

内存使用量再次降至正常水平。并且所有AspectJExpressionPointcut实例总共花费不到1MB。

有人可以解释为什么会这样吗?为什么第一点切割表达还不够?为什么不共享AspectJExpressionPointcut的缓存?

1 个答案:

答案 0 :(得分:8)

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

另外,在提供特定bean的所有方法以查看是否存在切入点表达式匹配之前,Spring首先通过调用AspectJExpressionPointcut来检查bean类是否可以可能匹配。匹配(类targetClass)。 此方法委托AspectJ的PointcutExpressionImpl.couldPossiblyMatch()方法。这将执行快速检查一个类是否“可能”匹配切入点表达式或永远不会“定义”匹配。 根据AspectJ开发人员使用内部切入点,结果更明确没有。他们也recommend to never use a standalone kind of pointcuts (execution, call, get, set), but combine these with within

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

但至少你可以限制缓存的内容。我还认为,一旦applicationContext启动,Spring就可以通过不保留整个缓存来改进这一点。 F.E.当一个新的bean在它已经启动后动态添加到applicationContext时,它们可能会丢弃所有不匹配的代价,而不是重做一些匹配。

AspectJExpressionPointcut类中另一个可能的内存是pointCutParser。可以在applicationContext中的所有AspectJExpressionPointcuts中共享此解析器。在JIRA机票SPR-7678处获取战利品。