- 浏览: 3064 次
- 性别:
- 来自: 广州
最新评论
严重警告: 如果存在任何来自应用以外的引用,引用了由J2EE应用本身类加载器加载的类和类实例对象,那么ClassLoader类加载内存泄漏问题就出现了。
ClassLoader 类加载内存泄漏问题的定位
正如上所述Classloader类加载内存泄漏是由于不断重复地启动、停止应用导致Class多次加载,并由于系统一级对象引用的关系,导致以前创建的类无法被回收,从而导致内存泄漏。
定位ClassLoader 类加载内存泄漏的根源还是非常困难的,因为任何现有的JVM Profiling工具都不能通过ClassLoader的视角来分析当前内存中所存在的Class类。 目前我们只能通过产生JVM Heapdump的方式来鉴定是否存在ClassLoader 类加载内存泄漏,再通过以上ClassLoader 类加载内存泄漏产生的机理来排查可能出现问题的地方,最终解决问题。
好像在JDK6工具集中提供了相应的工具来定位问题。请参考http://blogs.sun.com/fkieviet/entry/how_to_fix_the_dreaded
为了简化大家排查和定位应用中可能存在ClassLoader 类加载内存泄漏的过程,为此我们罗列了一些能导致Classloader类加载内存泄漏的代码和组件:(我们此处就不铺开篇幅阐述下面组件导致内存泄漏的根源,就当作大家的作业吧!哈哈)
a) 应用或使用的组件中使用了java.util.logging.Level那你得注意了。
b) 如果使用了诸如DBCP等基于DriverManager API基础上开发的数据库连接池组件,如果底层设计考虑不周,极易引发Classloader类加载内存泄漏。
c) 如果你使用到了commons-logging组件(其实很多OpenSource组件都依赖于commons-logging),那十有八九 会出现Classloader类加载内存泄漏。因为在象WebSphere、Tomcat等服务器核心引擎中同样使用到了commons-logging 组件,并在应用启动之前commons-logging的很多类已经被系统级ClassLoader所加载。缺省状态下,一个类的加载是从JVM类加载器 开始的,这样系统commons-logging的优先级一般高于应用EAR中所包含的commons-logging,所以Classloader类加 载内存泄漏就有可能出现了。问题简单分析如下:
1) 我们一般在应用中使用commons-logging的API来获得Log:protected final Log logger = LogFactory.getLog (getClass())。
2) 为此我们分析commons-logging类库中LogFactory类,请注意其中factories
是类静态变量,而getFactory()方法是静态方法,都是属于类属性。
通过下面代码我们可以清晰的得知:如果LogFactory在应用EAR上一级
的
类加载路径中被加载,那么在应用类加载器加载、创建的LogFactory实例(不管
org.apache.commons.logging.impl.LogFactoryImpl还是
org.apache.commons.logging.impl.Log4jFactory),将会被上一级类加载器中的LogFactory类所强制
性地引用并存储在静态变量factories
的类属性中。
故而即使强行停止此EAR应用,但是由于系统类加载器加载的LogFactory中的factories
强制引用了此应用创建的LogFactory实例对象不能被进行垃圾回收,从导致所有的Class无法被销毁,最终形成Classloader类加载内存泄漏。
LogFactory.java
- public abstract class LogFactory {
- protected static Hashtable factories = null ;
- ……
- public static Log getLog(Class clazz) throws LogConfigurationException {
- return getFactory().getInstance(clazz);
- }
- public abstract Log getInstance(Class class1) throws LogConfigurationException;
- ……
- public static LogFactory getFactory() throws LogConfigurationException {
- ClassLoader contextClassLoader = getContextClassLoader();
- LogFactory factory = getCachedFactory(contextClassLoader);
- if (factory != null )
- return factory;
- ……
- //下面大量的代码被删除,主要用于:创建由应用加载的新LogFactory 对象 factory
- ……
- if (factory != null ) {
- cacheFactory(contextClassLoader, factory);
- ……
- }
- return factory;
- }
- private static void cacheFactory(ClassLoader classLoader, LogFactory factory) {
- if (factory != null )
- if (classLoader == null )
- nullClassLoaderFactory = factory;
- else
- factories.put(classLoader, factory);
- }
- ……
- }
d) 把log4j类库放置到系统类路径下(比如:JVM、WebSphere Extensions Class
loader、WebSphere lib/app Class loader、WebSphere "server" Class
loader类路径),并且使用log4j的“Context Repository Selector”模式来获得各个应用的logging配置。
如果此时应用EAR/WAR中包含log4j类库将会出现Class Cast
Exceptions异常不能正常运行;如果应用EAR/WAR中不包含log4j类库,虽然应用能够正常运行但是会导致Classloader类加载内
存泄漏。关于log4j的“Context Repository Selector”模式请参考http://www.qos.ch/logging/sc.jsp
e) 如果你开发的组件中使用了java.beans.Introspector来进行Class/Method MetaData的缓存,可能会引发Classloader类加载内存泄漏。
每次解析Java Bean 的属性、方法是比较耗CPU资源的,所以在很多的框架级组件如Spring中普遍使用java.beans.Introspector来Cache缓存JavaBean的定义,Introspector类中会使用private
static
Map beanInfoCache
= Collections.synchronizedMap
(new
WeakHashMap())类静态变量的方式来进行保存JavaBean的定义。
而Introspector是由系统JVM ClassLoader进行加载的,所以应用中定义的JavaBean Class将会被系统类加载器加载的Introspector强制引用,从而导致在应用被停止的状态下,所有与此应用相关的类无法被回收。
Introspector具体代码如下:
java.beans.Introspector.java
- package java.beans;
- ……
- public class Introspector {
- ……
- private static Map declaredMethodCache = Collections.synchronizedMap( new WeakHashMap());
- private static Map beanInfoCache = Collections.synchronizedMap( new WeakHashMap());
- ……
- public static BeanInfo getBeanInfo(Class<?> beanClass) throws IntrospectionException
- {
- if (!ReflectUtil.isPackageAccessible(beanClass)) {
- return ( new Introspector(beanClass, null , USE_ALL_BEANINFO)).getBeanInfo();
- }
- BeanInfo bi = (BeanInfo)beanInfoCache.get(beanClass);
- if (bi == null ) {
- bi = (new Introspector(beanClass, null , USE_ALL_BEANINFO)).getBeanInfo();
- beanInfoCache.put(beanClass, bi);
- }
- return bi;
- }
- ……
- }
我们同样可以在Spring org.springframework.beans.CachedIntrospectionResults类的注释中,清晰的得知Spring中可能会存在Introspection Classloader类加载内存泄漏:“
Internal
class that caches JavaBeans {@link java.beans.PropertyDescriptor}
information for a Java class. Not intended for direct use by
application code. Necessary for own caching of descriptors within the
application's ClassLoader, rather than rely on the JDK's system-wide
BeanInfo cache (in order to avoid leaks on ClassLoader shutdown).
”
在CachedIntrospectionResults中同样使用了类静态变量classCache来缓存类的定义,如果Spring的类库存在于应用类加载器上一级
的JVM系统或应用服务器类路径上,则有可能导致Classloader类加载内存泄漏。
CachedIntrospectionResults具体代码如下:
org.springframework.beans.CachedIntrospectionResults.java(注:针对Spring2.0.7以后的版本 )
- package org.springframework.beans;
- ......
- final class CachedIntrospectionResults
- {
- private static final Log logger;
- private static final Map classCache = Collections.synchronizedMap( new WeakHashMap());
- private final BeanInfo beanInfo;
- private final Map propertyDescriptorCache;
- static
- {logger = LogFactory.getLog(org.springframework.beans.CachedIntrospectionResults.class ); }
- public static CachedIntrospectionResults forClass(Class beanClass)
- throws BeansException
- {
- CachedIntrospectionResults results = null ;
- Object value = classCache.get(beanClass);
- ……
- if (results == null )
- {
- results = new CachedIntrospectionResults(beanClass);
- boolean cacheSafe = isCacheSafe(beanClass);
- if (logger.isDebugEnabled())
- logger.debug("Class [" + beanClass.getName() + "] is " + (cacheSafe ? "" : "not " ) + "cache-safe" );
- if (cacheSafe)
- classCache.put(beanClass, results);
- else
- classCache.put(beanClass, new WeakReference(results));
- } else
- if (logger.isDebugEnabled())
- logger.debug("Using cached introspection results for class [" + beanClass.getName() + "]" );
- return results;
- }
- private CachedIntrospectionResults(Class clazz) throws BeansException
- {
- ……
- beanInfo = Introspector.getBeanInfo(clazz);
- Class classToFlush = clazz;
- ……
- }
- ……
- }
f) 在commons-beanutils 1.7版本(包括1.7版本)的组件中存在Classloader类加载内存泄漏,只有最新的1.8.0Beta修正了此潜在的问题,
问题描述:
* [BEANUTILS-59] - Memory leak on webapp undeploy in WrapDynaClass
* [BEANUTILS-156] - Memory leak on webapp undeploy in MappedPropertyDescriptor
详细描述请参考:http://commons.apache.org/beanutils/v1.8.0-BETA/RELEASE-NOTES.txt
g) 在应用中使用了commons-beanutils 的MethodUtils来对类的方法Method进行操作,那同样存在Classloader类加载内存泄漏的可能。
如果commons-beanutils类库放置在应用上一级
的类加载路径中,并且有其他应用(或系统代码)在此应用之前
使用同样方式MethodUtils来对Class的Method进行操作(在其他类加载器上加载MethodUitls),那么Classloader类加载内存泄漏必然出现。我们可以参考MethodUtils对应代码,可以非常直观地定位问题:
- package org.apache.commons.beanutils;
- ……
- public class MethodUtils
- {
- private static WeakHashMap cache = new WeakHashMap();
- ……
- public static Method getAccessibleMethod(Class clazz, String methodName, Class parameterTypes[])
- {
- MethodDescriptor md;
- Method method;
- md = new MethodDescriptor(clazz, methodName, parameterTypes, true );
- method = (Method)cache.get(md);
- if (method != null )
- return method;
- try {
- method = getAccessibleMethod(clazz.getMethod(methodName, parameterTypes));
- cache.put(md, method);
- return method;
- }catch (NoSuchMethodException e){
- return null ;
- }
- ……
- }
h) 如果应用中使用到Java 1.5语法定义的 enum 类,而此定义的类放置在应用上一级 的类加载路径中。首先在我们开发的 应用类加载器中加载并初始化了应用中定义的enum类,随后其他应用EAR/WAR(或系统代码)也使用到此定义的enum类,在并把此类enum属性引 用放置到(针对其他应用的)类静态变量或Servlet类变量,那么我们开发应用的Classloader类加载器将不会被回收,最终内存泄漏必然出现。 举例如下:
OperationEnum.java
- package com.test.enumeration;
- public enum OperationEnum {
- QUOTE(1 ), ISSUE( 2 ), RENEW( 4 ), CANCEL( 12 ),
- ENDORSE(16 ), CHANGE( 64 ), REINSTATE( 192 );
- private int operation = 0 ;
- private OperationEnum( int op) {
- this .operation = op;
- }
- public boolean isNewOperation() {
- return ( this .operation== 2 ) ||
- (this .operation== 4 ) ||
- (this .operation== 192 );
- }
- }
其他EAR 应用中 使用到上面定义enum类的样例代码
- public class LeakCauseServletInOtherApp extends HttpServlet {
- private final OperationEnum operation = OperationEnum.CHANGE; //
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- doSomething(request, response);
- }
- ……
- }
i) 导致Classloader
类加载内存泄漏的另外一个重要因素就是
:如果在框架中或应用使用ThreadLocal线程数据空间来存储实例对象,你必须知道在WAS等应用服务器中线程实例都是属于池态的,是由应用服务器WebContainer等容器来维护这些线程实例。
即使应用被停止了,这些池态的线程实例仍然属于存活运行状态,如果应用Web Servlet线程运行过程中在ThreadLocal上存储的实例对象没有被正确删除,可能导致线程类加载内存泄漏问题。
在老版本的DOM4J
、Mozilla Rhino、CGLIB
都存在这种类型的线程内存泄漏,请使用这些组件的最新版本来避免此类泄漏问题的发生。
1) Hibernate 3.2.2版本中存在ThreadLocal 线程变量内存泄漏问题,在3.2.3版本中得到修订。详细内容请参考“Big memory leak in the use of CGLIB” http://opensource.atlassian.com/projects/hibernate/browse/HHH-2481
2) CGLIB 2.1存在ThreadLocal 线程变量内存泄漏问题,在最新的版本2.1_3中问题应该得到修订。详细内容请参考
http://sourceforge.net/tracker/index.php?func=detail&aid=1257327&group_id=56933&atid=482368
http://sourceforge.net/tracker/index.php?func=detail&aid=1291183&group_id=56933&atid=482370
http://jira.jboss.com/jira/browse/JBAS-2256
3) dom4j 1.6之前的版本存在ThreadLocal 线程变量内存泄漏问题,在1.6以后的版本中此问题得到解决。
问题描述:https://sourceforge.net/tracker/index.php?func=detail&aid=1070309&group_id=16035&atid=116035
Bug修订描述:“Added a SingletonStrategyclass for managing singletons. This
allows to use different strategies for singletons, like: one instance
per VM, one instance per thread, ... This change removed the usage of
ThreadLocals.”
http://www.dom4j.org/changes-report.html
ClassLoader 类加载内存泄漏问题的解决方案
ClassLoader类加载内存泄漏问题解决的基本原则:
1、 不要把应用使用的类库放置到JRE或WebSphere服务器的类加载器路径中,尽量把使用的类库保持在EAR 或WAR/WEB-INF/Lib路径中。
2、 尽量在WebSphere服务器中设置类加载顺序为“Child-First ClassLoaders”/“Parent-Last ClassLoaders”。
3、 针对DOM4J、Mozilla Rhino、CGLIB请确认使用最新的版本,并确认类库保存在应用EAR级别之下。
4、 尽量避免使用Java 1.5语法定义的 enum 类,如果使用了enum类,必须确认开发的类库保持在应用EAR类加载器这一级别之下,而千万不能放置到WebSphere或JVM类库路径中。
5、 使用最新版本的commons-logging,并确认类库保存在应用EAR级别之下。
6、 使用最新版本的commons-beanutils,并确认类库保存在应用EAR级别之下,千万不能放置到WebSphere或JVM类库路径中。
7、 使用最新版本的log4j,并确认类库保存在应用EAR级别之下,千万不能放置到WebSphere或JVM类库路径中。
8、 不要在生产环境中使用DriverManager。
9、 不要在生产环境中使用commons-dbcp作为数据源实现,推荐使用应用服务器提供的数据源。
10、 不要在应用中使用java.util.logging.Level。
由于无法避免commons-logging类库存在于WebSphere应用服务器类路径和大量J2EE OpenSource组件使用java.beans.Introspector来Cache缓存JavaBean定义的事实,针对这种情况我们如何来应对和处理呢?
就像我们上面为了再现Class重复加载问题而编写的ClassLoaderTestServlet样例中,使用最简单的方式调用有Spring管 理的类实例对象StaticClass sc,就发生了臭名昭著的Class类加载内存泄漏问题。我们如何来避免此问题的发生?
针对 java.beans.Introspector 内存泄漏问题
其实在Spring框架2.0.7 以后的版本中已经对此有了对应的解决方案,提供了一个专门处理 Java.beans.Introspector内存泄漏问题的辅助类: org.springframework.web.util.IntrospectorCleanupListener,并附有专门的文档进行说明说明。 文档原话如下:
“
Listener that flushes the JDK's JavaBeans Introspector cache on web app shutdown. Register this listener in your web.xml to guarantee proper release of the web application class loader and its loaded classes.
If the JavaBeans Introspector has been used to
analyze application classes, the system-level Introspector cache will
hold a hard reference to those classes. Consequently, those classes and
the web application class loader will not be garbage-collected on web
app shutdown!
This listener performs proper cleanup, to allow for garbage collection to take effect.
Unfortunately, the only way to clean up the Introspector is to flush the entire cache, as there is no way to specifically determine the application's classes referenced there. This will remove cached introspection results for all other applications in the server too.
Note that this listener is not necessary when using Spring's beans infrastructure within the application, as Spring's own introspection results cache will immediately flush an analyzed class from the JavaBeans Introspector cache and only hold a cache within the application's own ClassLoader. Although Spring itself does not create JDK Introspector leaks, note that this listener should nevertheless be used in scenarios where the Spring framework classes themselves reside in a 'common' ClassLoader (such as the system ClassLoader ). In such a scenario, this listener will properly clean up Spring's introspection cache.
Application classes hardly ever need to use the JavaBeans Introspector directly, so are normally not the cause of Introspector resource leaks. Rather, many libraries and frameworks do not clean up the Introspector: e.g. Struts and Quartz.
Note that a single such Introspector leak will cause the entire web app class loader to not get garbage collected! This has the consequence that you will see all the application's static class resources (like singletons) around after web app shutdown, which is not the fault of those classes!
This listener should be registered as the first one in web.xml , before any application listeners such as Spring's ContextLoaderListener. This allows the listener to take full effect at the right time of the lifecycle.
”
在上面的文档中,我们可以清晰的得知,如果把Spring类库放置到JVM系统或应用服务器一级别的类库路径中,我们必须在web.xml中配置 org.springframework.web.util.IntrospectorCleanupListener,才能防止Spring中可能存在 的Introspector内存泄漏。
web.xml样例配置如下:
web.xml配置文件 (此 Spring Listener 只有在Spring2.0 以后的版本才存在 )
- <? xml version = "1.0" encoding = "UTF-8" ?>
- < web-app id = "WebApp_ID" version = "2.4"
- xmlns = "http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
- < display-name > ClassLoader </ display-name >
- < context-param >
- < param-name > contextConfigLocation </ param-name >
- < param-value > classpath*:spring/*.xml </ param-value >
- </ context-param >
- <!-- Spring 刷新Introspector防止内存泄露,推荐把此Listener放置在第一个,至少是Spring相关 Listener的第一个 -->
- < listener >
- < listener-class > org.springframework.web.util.IntrospectorCleanupListener </ listener-class >
- </ listener >
- < listener >
- < listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class >
- </ listener >
- ……
org.springframework.web.util.IntrospectorCleanupListener样例代码如下:
IntrospectorCleanupListener.java (为Spring 2.0.7 以后版本的代码 )
- package org.springframework.web.util;
- ……
- public class IntrospectorCleanupListener implements ServletContextListener {
- public void contextInitialized(ServletContextEvent event) {
- CachedIntrospectionResults.acceptClassLoader(Thread.currentThread().getContextClassLoader());
- }
- public void contextDestroyed(ServletContextEvent event) {
- CachedIntrospectionResults.clearClassLoader(Thread.currentThread().getContextClassLoader());
- Introspector.flushCaches();
- }
- }
针对 WebSphere 应用服务器类路径中存在 commons-logging 类库,应用中 commons-logging 的使用导致 ClassLoader 类加载内存泄漏问题
其实针对上面编写ClassLoaderTestServlet样例的EAR应用,我们在测试过程中并没有把Spring类库放置到 WebSphere应用服务器或JVM系统类库路径中,Spring类库仅仅存在于应用的WEB-INF/lib目录中(即:应用的类加载范围内),那为 什么还出现类加载内存泄漏?应该不是由Introspector内存泄漏问题引起的!
通过分析Spring源代码得知,Spring Bean定义加载诸如ClassPathXmlApplicationContext等类的父类AbstractApplicationContext中 使用了commons-logging组件来进行框架日志记录,所以ClassLoaderTestServlet样例测试中的内存泄漏是由 commons-logging导致的。
那么,我们如何避免commons-logging内存泄漏?
其实我们可以仿照上面Spring 框架中针对Introspector泄漏问题的解决方案,编写一个ServletContextListener来监听Servlet容器的生命周期,一 旦发现WebContainer被终止,我们可以主动释放存储在LogFactory类静态变量factories中所有由此应用产生的类实例对象,最终 解决commons-logging内存泄漏。
用于清除LogFactory类静态变量factories中实例对象的代码如下:
ApplicationLifecycleListener.java
- package com.test;
- import javax.servlet.ServletContextEvent;
- import javax.servlet.ServletContextListener;
- import org.apache.commons.logging.LogFactory;
- public class ApplicationLifecycleListener implements ServletContextListener {
- public void contextDestroyed( final ServletContextEvent sce) {
- LogFactory.release(Thread.currentThread().getContextClassLoader());
- }
- public void contextInitialized( final ServletContextEvent sce) {
- }
- }
当然我们必须把此ServletContextListener 注册到web.xml 中,web.xml样例配置如下:
web.xml配置文件
- <? xml version = "1.0" encoding = "UTF-8" ?>
- < web-app id = "WebApp_ID" version = "2.4"
- xmlns = "http://java.sun.com/xml/ns/j2ee"
- xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
- < display-name > ClassLoader </ display-name >
- < context-param >
- < param-name > contextConfigLocation </ param-name >
- < param-value > classpath*:spring/*.xml </ param-value >
- </ context-param >
- <!-- Spring 刷新Introspector防止内存泄露,推荐把此Listener放置在第一个,至少是Spring相关 Listener的第一个 -->
- < listener >
- < listener-class > org.springframework.web.util.IntrospectorCleanupListener </ listener-class >
- </ listener >
- < listener >
- < listener-class > org.springframework.web.context.ContextLoaderListener </ listener-class >
- </ listener >
- < listener >
- < listener-class > com.test.ApplicationLifecycleListener </ listener-class >
- </ listener >
- ……
通过实验,我们最终解决了Spring标准应用中臭名昭著的ClassLoader类加载器内存泄漏问题。!
参考资料:
Tomcat和Websphere类加载机制
http://gocom.primeton.com/modules/newbb/item42595_42595.htm
JVM的垃圾回收机制详解和调优
http://www.builder.com.cn/2007/0824/468927.shtml
With updating ClassLoader several times, jdk1.4.1_05 server VM will be down with an error java.lang.OutOfMemoryError
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4957990
java.lang.OutOfMemoryError: PermGen space及其解决方法
http://www.wujianrong.com/archives/2006/12/javalangoutofmemoryerror_permg.html
OutOfMemory error when repetatively deploying and undeploying with 10 minute interval in JBoss Application Server
http://jira.jboss.com/jira/browse/JBAS-2299
How to fix the dreaded "java.lang.OutOfMemoryError: PermGen space" exception (classloader leaks)
http://blogs.sun.com/fkieviet/entry/how_to_fix_the_dreaded
Commons-logging Logging/UndeployMemoryLeak
http://wiki.apache.org/jakarta-commons/Logging/UndeployMemoryLeak?action=print
Supporting the log4j RepositorySelector in Servlet Containers
http://www.qos.ch/logging/sc.jsp
commons-logging Classloader and Memory Management
http://commons.apache.org/logging/guide.html#Classloader and Memory Management
Big memory leak in the use of CGLIB
http://opensource.atlassian.com/projects/hibernate/browse/HHH-2481
相关推荐
在Java世界中,类加载器...在编写自定义类加载器或者使用第三方库时,需谨慎处理类加载和资源释放,以防止潜在的内存泄漏问题。通过遵循最佳实践和适当的设计模式,我们可以确保Java应用程序的高效和稳定运行。
不正确的类加载器管理可能导致内存泄漏。当一个类加载器不再使用时,如果没有其他引用指向它,理论上应该被垃圾回收。但是,如果这个类加载器加载的类还在使用,那么类加载器就无法被回收,这可能会导致资源浪费。...
在IT行业中,类卸载(Class Unloading)是Java虚拟机(JVM)内存管理的一个重要概念,尤其是在探讨垃圾收集(Garbage Collection)和应用程序性能优化时。标题" class-un-loading.tar.gz "暗示了这个压缩包可能包含...
本文将针对一个具体案例——浪潮烟草技术人员处理的广东烟草12月10日内存溢出事件,深入探讨Java虚拟机(JVM)中的Class类加载器内存泄露问题,并提出相应的解决方案。 #### 问题描述 在该事件中,技术人员发现了一...
这导致了类加载器的泄漏问题,需要注意对类加载器的生命周期管理。 7. **类加载器的源码分析** 对于深入理解类加载器的工作原理,阅读和分析JDK源码是非常有帮助的。例如,`java.lang.ClassLoader`的`loadClass()`...
本篇笔记将深入探讨`Application`对象的使用,包括如何利用它进行数据传递以及如何避免常见的内存泄漏问题。 首先,让我们了解`Application`的基本概念。在Android系统启动时,会先创建`Application`实例,然后依次...
在本文中,我们将深入探讨JVM的类加载子系统及其在内存管理中的作用。 类加载子系统,也被称为Class Loader SubSystem,其主要任务是从文件系统或网络中加载Class Files,这些文件是Java类的二进制表示。每个Class ...
本篇文章将通过一个简单的"JVM模拟内存泄漏代码"来深入探讨堆内存泄漏和元空间泄漏,帮助开发者理解和预防这类问题。 堆内存泄漏是指程序中的对象在不再被使用后,由于某些原因没有被垃圾收集器回收,导致堆内存...
内存泄露是Android应用开发中的一个重要问题,它会导致应用性能下降,甚至引发应用程序崩溃。内存泄露通常发生在对象不再被使用但仍然被引用,使得垃圾收集器(GC)无法释放这些资源。本文将深入探讨两个常见的内存...
总的来说,《Thinking in Java 5 - The Class object》这部分内容深入探讨了Java中关于类对象的核心概念,包括反射、类加载器和类的生命周期。理解这些知识不仅能够提高编程效率,还能让你在面对复杂问题时有更多的...
类加载器是JVM的一个组成部分,负责加载Java类到内存中。加载过程包括五个步骤: 1. **加载**:从磁盘读取字节码文件(`.class`)到内存。 2. **验证**:确保字节码文件符合Java语法规则和安全限制。 3. **准备**:...
类加载机制是Java虚拟机(JVM)运行时的核心机制之一,它负责将类的.class文件从磁盘或网络中加载到内存,...通过深入学习和实践,我们可以更好地优化程序性能,避免内存泄漏,甚至实现自定义类加载器以满足特定需求。
主要有Bootstrap ClassLoader(启动类加载器)、Extension ClassLoader(扩展类加载器)和AppClassLoader(应用程序类加载器)。 7. **内存溢出与泄漏**: - 内存溢出(Out Of Memory,OOM)是由于程序分配的内存...
Java虚拟机(JVM)性能优化是Java开发者...掌握JVM的这些基础知识对于优化Java应用性能、解决内存泄漏和避免类加载异常等问题至关重要,也是求职面试中的常见考点。了解这些概念有助于开发更高效、稳定的Java应用程序。
1. 类加载器:负责加载.class文件到JVM内存中,分为启动类加载器、扩展类加载器和应用程序类加载器,以及用户自定义的类加载器。 2. 运行时数据区:包括堆内存、栈内存、方法区、程序计数器和本地方法栈。其中,堆...
在使用`ThreadLocal`时,一定要确保在恰当的时机清除其存储的引用,以避免长期持有不必要的类加载器实例,导致内存资源浪费。在Java EE环境中,尤其需要注意这类问题,因为容器的特殊性可能导致不易察觉的内存泄漏。...
类加载器负责将.class文件加载到JVM内存中。Java的类加载机制采用双亲委托模型,即先由父加载器尝试加载,如果失败再由子加载器进行加载。类加载器分为引导类加载器、扩展类加载器和应用程序类加载器,以及用户...
- **类加载器**:负责加载类的二进制字节流到JVM中,包括启动类加载器、扩展类加载器和应用程序类加载器等。 - **执行引擎**:执行Java字节码,包括解释器和即时编译器(JIT)。 - **运行时数据区**:存储程序...
同时,通过分析JVM的内存快照和日志,可以定位和解决内存泄漏、性能瓶颈等问题。 总的来说,JVM解析编译过的class文件是一个复杂的过程,涉及众多细节。开发者不仅要理解编译过程,还需要熟悉JVM的内部机制,才能更...
本知识汇总将深入探讨JVM的类加载机制、内存分配、类变量的存储、类加载器以及内存回收等核心概念。 首先,我们来了解**类加载机制**。Java程序在运行时,会经历加载、验证、准备、解析和初始化五个阶段。加载是将...