b.Jre Memory Leak Prevention Listener

本文我们来分析分析应用服务器的内存泄露的问题,看看Tomcat是如何应对这个问题的;

首先,来看看内存泄露这个词,内存对于java程序来说,即指JVM内存,而我们知道JVM的内存泄露是有很多种情况的;

一种情况,class泄露是perm区的内存,此种场景就是当应用服务器的类特别多的时候,perm区的容量也是由限度的,会撑爆;

另外一种就是,java对象太多,新生代,老年代等对象存储区太多,full GC都已经收拾不了这种残局;

上述的两种情况,最终都会导致OOM溢出;

而作为Tomcat来讲,如何避免这种溢出,就是这个 Jre Memory Leak Prevention Listener 的能力了;

对于第一种class的情况,Jre Memory Leak Prevention Listener将class的加载优先放在系统类加载器这一级中,来解决这个问题;

回过头来,我们先看看Tomcat的class层级结构就可以明白:

作为每一个应用的WebappClassLoader,如果要加载同样的类库和class,相当于每一份ClassLoader中都得加载一遍,而无论是哪来的ClassLoader,只要再同一个JVm下,都会占用perm区的资源;

如果每个应用中的加载的类库版本不同还好说,或者加载的库千差万别也好说,那么每一个WebappClassLoader都加载一遍这些Class没有其他的办法;

而一般如log4j,sax-dom的xml解析,jdbc驱动等等这些非常常用的类库,很多应用都一样;

因此,我们一般在开发应用的时候,技术经理总会说,有没有什么通用的库和lib包,都要放到common目录下面就是这个道理;

Jre Memory Leak Prevention Listener和上述的思路类似,其主要会将一些常用的class资源泄露的库优先加载;

如下面的一段代码:

classToInitialize属性是以,分隔的一串字符串的配置,实际的意思就是预先加载的一系列的类;

你可以在Jre Memory Leak Prevention Listener中进行配置,然后优先在系统ClassLoader中进行加载;

说到这里,Jre Memory Leak Prevention Listener的整体流程是先保存原来的线程上下文的classloader,然后直接进行切换,最后再切换回来:

对于第二种情况,也就是内存泄露是不是因为class的问题,而是因为java对象太多造成的;

其实也可以借鉴class的处理办法,即很多库,特别是java的库中,JDBC驱动库这种通用库中,例如数据驱动的初始化,如果在应用类加载器中进行初始化,这些都会产生n多个对象,我们不妨将其优先在系统类加载器中加载,这样如果该对象在查找的时候,直接通过双亲委派查找到了系统ClassLoader加载的类,对于类中引用的静态对象资源直接进行初始化,这样应用中的查找到该类的时候,相当于是已经初始化过的类引用的静态资源,这样大大减少了降低java对象的作用,使其只有一份;

如DriverManager的启动:

如果是应用类加载器进行加载,不同应用中可能将其注册的驱动实现类加载到自己的应用类加载器中,并进行初始化,类的增多暂且不说,这一系列的操作会搞出很多对象出来;

而通过这种“预热”的机制,一下子就把所有的驱动进行初始化了,而在应用中无非也是这么调用API,所以这样就相当于减少了n多个对象的创建;

类似的机制还有很多,Jre Memory Leak Prevention Listener还可以减少一些线程创建,其思路也是也是这种将每一个应用的线程变成只有一份线程;

我们来看看配置:

JRE Memory Leak Prevention Listener - org.apache.catalina.core.JreMemoryLeakPreventionListener

The JRE Memory Leak Prevention Listener provides work-arounds for known places where the Java Runtime environment uses the context class loader to load a singleton as this will cause a memory leak if a web application class loader happens to be the context class loader at the time. The work-around is to initialise these singletons when this listener starts as Tomcat‘s common class loader is the context class loader at that time. It also provides work-arounds for known issues that can result in locked JAR files.

This listener must only be nested within Server elements.

需要注意,Jre Memory Leak Prevention Listener 只能配置在<Server>中;

The following additional attributes are supported by the JRE Memory Leak Prevention Listener:

Attribute Description
appContextProtection
Enables protection so that calls to sun.awt.AppContext.getAppContext() triggered by a web application do not result in a memory leak. Note that enabling this protection will trigger a requirement for a graphical environment unless Java is started in head-less mode. The default is false. This protection is disabled if running on Java 8 onwards since the leak has been fixed for Java 8 onwards.

web应用多次执行sun.awt.AppContext.getAppContext()会造成泄露,这里需要进行一下保护,代码为:

AWTThreadProtection
Enables protection so that calls to java.awt.Toolkit.getDefaultToolkit() triggered by a web application do not result in a memory leak. Defaults to false because an AWT thread is launched. This protection is disabled if running on Java 9 onwards since the leak has been fixed for Java 9 onwards.

web应用多次执行java.awt.Toolkit.getDefaultToolkit() 会造成内存泄露,保护代码为:

classesToInitialize
List of comma-separated fully qualified class names to load and initialize during the startup of this Listener. This allows to pre-load classes that are known to provoke classloader leaks if they are loaded during a request processing. Non-JRE classes may be referenced, like oracle.jdbc.driver.OracleTimeoutThreadPerVM. The default value is empty, but specific JRE classes are loaded by other leak protection features managed by other attributes of this Listener.

预先通过系统类加载器加载的类,以逗号分隔,这样类就不会有多份了,相当于减少perm区的占用;

代码见上;

driverManagerProtection
The first use of java.sql.DriverManager will trigger the loading of JDBC Driver in the current class loader. The web application level memory leak protection can take care of this in most cases but triggering the loading here has fewer side-effects. The default is true.

数据库驱动的初始化先搞一轮,驱动的实现就不会每一个应用一份,减少对象创建;

代码见上;

gcDaemonProtection
Enables protection so that calls to sun.misc.GC.requestLatency(long) triggered by a web application do not result in a memory leak. Use of RMI is likely to trigger a call to this method. A side effect of enabling this protection is the creation of a thread named "GC Daemon". The protection uses reflection to access internal Sun classes and may generate errors on startup on non-Sun JVMs. The default is true. This protection is disabled if running on Java 9 onwards since the leak has been fixed for Java 9 onwards.

作为SUN的JDK,在进行GC请求的时候,会调用sun.misc.GC.requestLatency(long)  ;

而调用完这个方法之后,SUN的实现会启动一个daemon线程;

试想一下,如果每一个应用调用这段代码的话,即很容易产生内存泄露;

ldapPoolProtection
Enables protection so that the PoolCleaner thread started by com.sun.jndi.ldap.LdapPoolManager does not result in a memory leak. The thread is started the first time the LdapPoolManager class is used if the system property com.sun.jndi.ldap.connect.pool.timeout is set to a value greater than 0. Without this protection, if a web application uses this class the PoolCleaner thread will be configured with the thread‘s context class loader set to the web application class loader which in turn will trigger a memory leak on reload. Defaults to true. This protection is disabled if running on Java 9 onwards since the leak has been fixed for Java 9 onwards.

Ldap的池中的PoolCleaner 线程如果每一个应用的应用classLoader加载极容易出现内存泄露;

securityLoginConfigurationProtection
Enables protection so that usage of the javax.security.auth.login.Configuration class by a web application does not provoke a memory leak. The first access of this class will trigger the initializer that will retain a static reference to the context class loader. The protection loads the class with the system class loader to ensure that the static initializer is not triggered by a web application. Defaults to true. This protection is disabled if running on Java 8 onwards since the leak has been fixed for Java 8 onwards.

让系统类加载器就把Configuration  初始化了,可以保证静态的initializer  不被web应用的类加载器调用,保证只有1份;

securityPolicyProtection
Enables protection so that usage of the deprecated javax.security.auth.Policy class by a web application does not result in a memory leak. The first access of this class will trigger the static initializer that will retain a static reference to the context class loader. The protection calls the getPolicy() method of this class to ensure that the static initializer is not triggered by a web application. Defaults to true.

Note: The underlying leak has been fixed in Java 7 update 51 onwards and Java 8 onwards. This protection is therefor disabled if running on Java 8 onwards.

Policy 的配置,和上一个securityLoginConfigurationProtection的配置一个意思;

tokenPollerProtection
Enables protection so that any token poller thread initialized by sun.security.pkcs11.SunPKCS11.initToken() does not result in a memory leak. The thread is started depending on various conditions as part of the initialization of the Java Cryptography Architecture. Without the protection this can happen during Webapp deployment when the MessageDigest for generating session IDs is initialized. As a result the thread has the Webapp class loader as its thread context class loader. Enabling the protection initializes JCA early during Tomcat startup. Defaults to true. This protection is disabled if running on Java 9 onwards since the leak has been fixed for Java 9 onwards.

减少Java Cryptography Architecture的线程,不创建那么多个tokenPollerProtection线程;

urlCacheProtection
Enables protection so that reading resources from JAR files using java.net.URLConnections does not result in the JAR file being locked. Note that enabling this protection disables caching by default for all resources obtained via java.net.URLConnections. Caching may be re-enabled on a case by case basis as required. Defaults to true.

在读取jar文件的时候,极容易造成lock文件,而实质原因是jarConnection中缓存默认设置没有禁用;

解决办法就是找一个根本不存在的jar链接,然后设置就OK了:

xmlParsingProtection
Enables protection so that parsing XML files within a web application does not result in a memory leak. Note that memory profilers may not display the GC root associated with this leak making it particularly hard to diagnose. Defaults to true. This protection is disabled if running on Java 9 onwards since the leak has been fixed for Java 9 onwards.

尽可能的多初始化dom实现的内容,减少对象;

总结一下,其实Jre Memory Leak Prevention Listener主要做的就是让多份内存变成1份内存,方法有很多,线程减少,提高classloader加载的层级,提前预热,甚至我们通过Jre Memory Leak Prevention Listener的代码来发现,其还能解锁jar文件。。。

看似貌似是很神奇的,但可以看到,这里面大多数与实际的具体实现框架有关,如SUN.xxx,和特定的JDK版本的实现缺陷有关,很多属性在JAVA 9中都被新版本JDK所修复了,因此该配置也没有意义;

而值得注意的一点是,对于gcDaemonProtection 这个属性,在特定版本的JDK下,配置还会造成频繁GC,如邮件:

http://mail-archives.apache.org/mod_mbox/tomcat-users/201008.mbox/%[email protected]%3E

因此,对这些属性需要逐个去分析和研究一下,本文由于篇幅的限制并没有逐个去研究,这个空间就留给各位读者了;

来自为知笔记(Wiz)

原文地址:https://www.cnblogs.com/yuantongaaaaaa/p/10313326.html

时间: 2024-08-07 18:35:59

b.Jre Memory Leak Prevention Listener的相关文章

To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

1.错误描述 严重: The web application [/AMST] registered the JDBC driver [org.logicalcobwebs.proxool.ProxoolDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered. 八

大神的---解决tomcat内存溢出问题----tomcat报错:This is very likely to create a memory leak问题解决

tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因  在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样. 这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种情况:  1.OutOfMemoryError: Java heap space  2.OutOfMemoryError: PermGen space  3.OutOfMemoryError: unab

tomcat 6.0.44 &ldquo;has failed to stop it. This is very likely to create a memory leak&rdquo; 问题调查

1. 问题起因 我们项目中缓存模块某个实现采用了ehcache(2.4.3),当项目部署到tomcat中后,对tomcat做停止服务操作,发现tomcat不能正常停止,报错 appears to have started a thread named [xxx] but has failed to stop it. This is very likely to create a memory leak.java进程不能正常结束,需要手动kill进程. 信息: Stopping service C

tomcat报错:This is very likely to create a memory leak问题解决

tomcat memory leak解决方案 这种问题在开发中经常会碰到的,看看前辈的总结经验 Tomcat内存溢出的原因  在生产环境中tomcat内存设置不好很容易出现内存溢出.造成内存溢出是不一样的,当然处理方式也不一样.  这里根据平时遇到的情况和相关资料进行一个总结.常见的一般会有下面三种情况:  1.OutOfMemoryError: Java heap space  2.OutOfMemoryError: PermGen space  3.OutOfMemoryError: una

Tomcat运行一段时间后,自动停止关闭,To prevent a memory leak,Druid 数据库连接自动关闭, the JDBC Driver has been forcibly unregistered.

1. Tomcat 错误日志 tail -100f tomcat9/logs/catalina.out 21-Sep-2017 23:05:39.301 INFO [Thread-5] org.apache.coyote.AbstractProtocol.pause Pausing ProtocolHandler ["ajp-nio-8809"]21-Sep-2017 23:05:39.352 INFO [Thread-5] org.apache.catalina.core.Stand

Memory Leak Detection in Embedded Systems

One of the problems with developing embedded systems is the detection of memory leaks; I've found three tools that are useful for this. These tools are used to detect application program errors, not kernel memory leaks. Two of these tools (mtrace and

【Valgrind】How to check memory leak and where it&#39;s in 10 mins

1. Install sudo apt-get install valgrind 2. If memory leak example code: /* memleak.c */ #include <stdlib.h> void* memleak(int n) { void *p = malloc(n); return p; } memleak.c /* main.c */ #include <stdio.h> #include <stdlib.h> void* meml

警告: The web application [ROOT] appears to have started a thread named [Thread-48] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:

1. 问题描述 tomcat跑web项目(其中依赖java项目) 出现大量上述警告 项目起不来 关键字 memory leak 内存泄漏 2. 解决方案 难道是程序写的有问题? 最终 将tomcat VM参数中 内存调大 解决了 -Xms512m -Xmx512m -Xmn300m -Xss2048k -XX:PermSize=512m -XX:MaxPermSize=512m 需要根据机器的配置做相应调整

内存泄漏(memory leak)和内存溢出

1. 什么是内存泄漏(memory leak)? 指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况.内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费. 2. 两种类型的内存泄漏: 堆内存泄漏(Heap leak).对内存指的是程序运行中根据需要分配通过malloc,realloc new等从堆中分配的一块内存,再是完成后必须通过调用对应的 free或者delete 删掉.如果程序的设计的错误导致这部分内存没有被释放,