使用velocity并且没有配置toolboxmanager性能问题

来源:互联网 发布:淘宝申请售后退款 编辑:程序博客网 时间:2024/06/03 22:58

测试前提

a)     使用velocity并且没有配置toolboxmanager

b)     高并发(TPS:450)

c)      长时间(至少5个小时以上)

问题根因简要分析:

这个问题主要出现的主要场景是在长时间大压力下,并且在使用velocity时没有配置toolboxmanager,进入异常分支,不断打印信息

Velocity#info(String infoLog)方法的实现,

一句话:RuntimeSingleton.getLog().info(String infoLog);而RuntimeSingleton#getLog()方法返回的就是之前那个static的RuntimeInstance对象的HoldingLogChute,于是乎到这里真相已经大白,因为HoldingLogChute里面的日志对象永远都没有被回收的机会,由于对象都比较小,所以如果运行比较长的时间的话,一定会出现OOM

解决方案:

如果此类在spring中配置并且为单例,会出现以上问题;

如果此类没有在spring中进行配置且vilocity没有配置toolboxmanager,会出现描述的问题。

 

项目中如果之前没有使用toolboxmanager的话,需要添加了一个空的toolbox.xml文件,迂回解决此问题。

 

个人觉得规避这两个问题比较好的解决方案:

 

1、继承velocity.VelocityLayoutResult类,重写 setVelocityManager 方法,加上同步处理,在 struts.xml 中配置为重写后的类。


@Override    

public void setVelocityManager(VelocityManager mgr) {

        if (mgr != null && velocityManager == null) {

           synchronized (VelocityLayoutResult.class) {

                if (mgr != null && velocityManager == null) {

                   synchronized (VelocityLayoutResult.class) {

                        super.setVelocityManager(mgr);

                        this.velocityManager = mgr;

                        ServletContext ctx = ServletActionContext.getServletContext();

                        mgr.init(ctx);

                        VelocityEngine engine = velocityManager.getVelocityEngine();

                        defaultLayout = (String) engine.getProperty(PROPERTY_DEFAULT_LAYOUT);

                        layoutDir = (String) engine.getProperty(PROPERTY_LAYOUT_DIR);

                        outputEncoding = (String) engine.getProperty(OUTPUT_ENCODING);

                        inputEncoding = (String) engine.getProperty(INPUT_ENCODING);

                        if (!layoutDir.endsWith("/")) {

                            layoutDir += '/';

                        }

                        if (!layoutDir.startsWith("/")) {

                            layoutDir = "/" + layoutDir;

                        }

                        // for efficiency's sake, make defaultLayout a full path now

                        defaultLayout = layoutDir + defaultLayout;

                        errorTemplate = (String) engine.getProperty(PROPERTY_ERROR_TEMPLATE);

                    }

                }

            }

        }

    }

 

2、在spring中配置一个此类的bean(重写setVelocityManager 后):<bean class="velocity.VelocityLayoutResult" /> 。

这样struts始终会使用spring中这个单例,虽然每次请求还是会调用setVelocityManager方法,但velocityManager对象初始化一次后就不为空了,不会在执行方法里的代码。
 velocityManager这个对象本身在struts里就是个单例。