Tomcat MemoryLeak 问题

来源:互联网 发布:美业邦软件的弊端 编辑:程序博客网 时间:2024/05/22 03:19

Tomcat reload memoryleak 错误描述
错误描述
此现象发生在tomcat reload过程中多见。

我们的线上环境是使用jenkins远程部署,在部署重启中出现memory leak错误提示

环境:
tomcat7、jdk1.8

问题原因定位:
jvm默认定义了三种classloader,分别是bootstrap classloader、extension classloader、system classloader 。采用的是双亲委托机制进行加载。
tomcat7的加载模型如图
这里写图片描述
注意此处tomcat的类加载方式不完全遵循双亲委派模型,其中对于应用级别的加载各个web应用自己的类加载器(WebAppClassLoader)会优先加载,如果加载不到才走commonClassLoader走双亲方式。
当tomcat发生relaod的时候会执行org.apache.catalina.loader.WebappLoader下的backgroundProcess方法

  public void backgroundProcess() {        if (reloadable && modified()) {            try {                Thread.currentThread().setContextClassLoader                    (WebappLoader.class.getClassLoader());                if (container instanceof StandardContext) {                    ((StandardContext) container).reload();                }            } finally {                if (container.getLoader() != null) {                    Thread.currentThread().setContextClassLoader                        (container.getLoader().getClassLoader());                }            }        } else {            closeJARs(false);        }    } 

此处会判断reloadable 和modified(),即是否允许reload并且产生修改。再看下是如何reload的,此部分在org.apache.catalina.core.StandardContext下的reload方法

public synchronized void reload() {        // Validate our current component state        if (!getState().isAvailable())            throw new IllegalStateException                (sm.getString("standardContext.notStarted", getName()));        if(log.isInfoEnabled())            log.info(sm.getString("standardContext.reloadingStarted",                    getName()));        // Stop accepting requests temporarily.        setPaused(true);        try {            stop();        } catch (LifecycleException e) {            log.error(                sm.getString("standardContext.stoppingContext", getName()), e);        }        try {            start();        } catch (LifecycleException e) {            log.error(                sm.getString("standardContext.startingContext", getName()), e);        }        setPaused(false);        if(log.isInfoEnabled())            log.info(sm.getString("standardContext.reloadingCompleted",                    getName()));    }

那么再回到问题quartz等线程没有被回收,重启前还有在其他地方引用的线程则gc无法回收。就会报上述错误。

解决方法:
1、应用使用的jesery,检测在servlet关闭的时候处理你要关闭的对象和线程

public void contextDestroyed(ServletContextEvent sce) {        // TODO Auto-generated method stub        System.out.println("reload Tomcat .... waiting >>>>  manual close  to prevent memory leak !!!!!!  ---  Today ");         //sql         this.shutDownSql();         //Jms         this.shutDownJms();         //Quertz         this.shutDownQuertz();         //Thread         this.shutDownThread();         System.out.println("reload Tomcat .... over >>>>  Its a happy day !!!  ---  Today");    }

2、Tomcat的实现是通过WeakHashMap来实现弱引用的,将WebappClassLoader对象放置到WeakHashMap中

private Map<ClassLoader, String> childClassLoaders = new WeakHashMap<ClassLoader, String>();public String[] findReloadedContextMemoryLeaks() {        List<String> result = new ArrayList<String>();        for (Map.Entry<ClassLoader, String> entry : childClassLoaders.entrySet()) {            ClassLoader cl = entry.getKey();            if (!((WebappClassLoader) cl).isStarted()) {                result.add(entry.getValue());            }        }        return result.toArray(new String[result.size()]);    }
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 网销客户不说话怎么办 两岁宝宝不说话怎么办? 4岁儿童说话结巴怎么办 3岁宝宝说话结巴怎么办 6岁儿童舌头短怎么办 5岁宝宝说话结巴怎么办 两岁宝宝说话晚怎么办 6岁儿童说话结巴怎么办 2岁宝宝呕吐拉稀怎么办 2岁宝宝突然呕吐怎么办 2岁宝宝呕吐发烧怎么办 2岁宝宝呕吐厉害怎么办 1岁宝宝半夜呕吐怎么办 2岁半宝宝呕吐怎么办 2岁宝宝半夜呕吐怎么办 两岁宝宝一直吐怎么办 原画师老了以后怎么办 孩子不想上学怎么办怎么去说服 嫉妒别人比我好怎么办 三岁宝宝爱打人怎么办 1岁宝宝喜欢打人怎么办 ps图层解锁不了怎么办 沈腾结婚马丽怎么办 延长甲没有纸托怎么办 高考第一志愿没录取怎么办 电子画颜料干了怎么办 数字画颜料干了怎么办 彩砂纸画不好了怎么办 宝宝吃了油画棒怎么办 2岁宝宝不爱刷牙怎么办 两岁宝宝不刷牙怎么办 1岁宝宝不爱刷牙怎么办 3岁宝宝不肯刷牙怎么办 20岁没学历迷茫怎么办 四岁了不长头发怎么办 17岁掉头发严重怎么办 头发很油,又少怎么办 25岁头发变稀怎么办 宝宝头发少又黄怎么办 头旋附近头发少怎么办 25岁掉头发严重怎么办