ViewResolver引起的内存泄漏

ViewResolver与Redirect引起的内存泄漏

最近在生产环境中发现一个使用spring mvc的应用由于内存泄漏挂掉了。与大家分享一下我们发现的问题与解决方式

生产监控的现象

  1. 半个月内,内存的总体用量在不断上升,并且full GC频繁。
  2. 通过ha分析dump文件发现一个大量占用内存的对象,
    在InternalResourceViewResolver对象中有一个hashMap包含多达四十万条记录,占用了98%的总体内存。

出现问题的应用功能介绍

  1. 应用负责一个相对独立的业务逻辑,所以web页面与java共同打在一个包内部署。
  2. 可以展示一些H5页面。
  3. java服务会将一些加密后的信息拼在url中,并发送redirect请求。

问题出现的原因

spring mvc通过ViewResolver和View来处理视图,在没有指定特殊的ViewResolver时,
默认使用InternalResourceViewResolver作为缺省的Resolver
而InternalResourceViewResolver继承自AbstractCachingViewResolver。
AbstractCachingViewResolver会将它曾经解析过的视图保持起来,以view的名称作为KEY。
每次要解析视图时先检查缓存,如果没有命中缓存则创建一个新视图并加入缓存中。以提高解析视图的性能。


public View resolveViewName(String viewName, Locale locale) throws Exception {
        if(!this.isCache()) {
            return this.createView(viewName, locale);
        } else {
            Object cacheKey = this.getCacheKey(viewName, locale);
            View view = (View)this.viewAccessCache.get(cacheKey);
            if(view == null) {
                Map var5 = this.viewCreationCache;
                synchronized(this.viewCreationCache) {
                    view = (View)this.viewCreationCache.get(cacheKey);
                    if(view == null) {
                        view = this.createView(viewName, locale);
                        if(view == null && this.cacheUnresolved) {
                            view = UNRESOLVED_VIEW;
                        }
                        if(view != null) {
                            this.viewAccessCache.put(cacheKey, view);
                            this.viewCreationCache.put(cacheKey, view);
                            if(this.logger.isTraceEnabled()) {
                                this.logger.trace("Cached view [" + cacheKey + "]");
                            }
                        }
                    }
                }
            }

            return view != UNRESOLVED_VIEW?view:null;
        }
    }

然而在我们的应用场景下,url中包含了部分加密信息,每个redirectUrl都是不同的,那么每一个view也都是不同的,viewResolver将在缓存中插入大量的view。最终
导致内存耗尽,应用挂掉。

解决方式

在这里为大家提供几种解决方式。
1. 简单粗暴:将AbstractCachingViewResolver的cacheLimit属性设为0,以后任何view都不会被缓存(性能下降)。

  1. 由于我们的应用还会提供一些H5页面服务,所以需要采用一些更优雅的方式解决这个问题

    1. 重写一个类myViewResolver继承默认ViewResolver(InternalResourceViewResolver)。
    2. 重写父类AbstractCachingViewResolver的resolveViewName方法.
    3. 将myViewResolver设为默认的ViewResolver。

      public class myViewResolver extends InternalResourceViewResolver {

    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
    if (viewName.startsWith(“redirect”)){
    return createView(viewName, locale);
    }
    return super.resolveViewName(viewName, locale);
    }
    这样一来,当生成的vivew是redirect时,直接创建一个新的view并返回不放入缓存中。如果是其他的view则还是原来的处理方式,放入缓存中进行加速。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值