对org.springframework.beans.CachedIntrospectionResults
这个类在spring2.01前没有被改写,spring2.06似乎已经改写了,还未看源码。不过这不是我所在意的问题。我在《org.springframework.beans简单解读》中的对这个类的理解是不正确的。我们先看看Guillaume Poirier对这个类中为什么使用
WeakHashMap的解释:
WeakHashMap is implemented with WeakReference for keys, and strong reference for values. That means if the value has a strong reference on the key, then the key cannot be garbage collected until the WeakHashMap is ready for collection. However, if the value has no strong reference on its key, then being in the WeakHashMap won't prevent the key and value from being garbage collected if it is otherwise ready. The WeakHashMap knows when to remove the key (and the value with it) by using the notification provided by the java.lang.ref package. For more information on this, see:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ref/package-summary.html
So the problem here with the CachedIntrospectionResults is that it uses BeanInfo and PropertyDescriptor that both have strong reference to the class (indirectly by a reference on Methods of the class). That will be solved with JDK 1.5 that uses a combinaison of Weak and Soft Reference to the Class and Method objects, but for 1.4.2, there's not really any better solution than to flush the Introspector's cache and/or use WeakReference on CachedIntrospectionResults. Using WeakReference on the CachedIntrospectionResults is safer, but decrease performance, and in such case a manual Instrospector.flushFromCaches(Class) must be used, so that the Instrospector does not keep a strong reference on the BeanInfo.
When a webapp is hot-redeployed, a new ClassLoader is created to load the webapp, and the old one is thrown away, expected to be garbage collected. For the collection to happen, the server must clear any strong reference to the ClassLoader or its classes, and also the webapp must make sure that any code in parent ClassLoaders (or siblings) clear any reference it might have to any of the webapp's class.
照他的说法和参考《深入JVM》一书,对Class有强引用的有:ClassLoader,java.beans.BeanInfo,java.beans.PropertyDescriptor,java.lang.reflect.Method。因为在这个缓存中使用Class作为key,而Value是CachedIntrospectionResults,CachedIntrospectionResults中持有BeanInfo和Method的引用,这两个都对Class对象有强引用(这一点据说在jdk5中已经修改,被改成软引用和弱引用的组合,而在jdk1.4.2需要这样的处理),导致在web应用关闭或者热部署的时候,旧的ClassLoader和它引用的类不能被回收,因此使用弱引用包装CachedIntrospectionResults对象作为Value。web应用关闭或者热部署的时候,会new新的ClassLoader用于装载类,这就是CachedIntrospectionResults判断缓存是否safe的根据所在,判断要缓存的Class引用的ClassLoader是否相同。
当使用JavaBean的内省时,使用Introspector,jdk会自动缓存内省的信息(BeanInfo),这一点可以理解,因为内省通过反射的代价是高昂的。当ClassLoader关闭的时候,Introspector的缓存持有BeanInfo的信息,而BeanInfo持有Class的强引用,这将导致ClassLoader和它引用的Class等对象不能被垃圾收集器回收,因此在关闭前,需要手工清除Introspector中的缓存,调用Introspector.flushFromCaches,这就是CachedIntrospectionResults中当得到BeanInfo后为什么要执行下面这段代码的原因:
this.beanInfo = Introspector.getBeanInfo(clazz);
// Immediately remove class from Introspector cache, to allow for proper
// garbage collection on class loader shutdown - we cache it here anyway,
// in a GC-friendly manner. In contrast to CachedIntrospectionResults,
// Introspector does not use WeakReferences as values of its WeakHashMap!
Class classToFlush = clazz;
do {
Introspector.flushFromCaches(classToFlush);
classToFlush = classToFlush.getSuperclass();
}
while (classToFlush != null);
说到这里,spring中有一个比较少人注意的Listener——
org.springframework.web.util.IntrospectorCleanupListener,这个类的说明如下:
它是一个在web应用关闭的时候,清除JavaBeans Introspector缓存的监听器.在web.xml中注册这个listener.可以保证在web 应用关闭的时候释放与掉这个web 应用相关的class loader 和由它加载的类
如果你使用了JavaBeans Introspector来分析应用中的类,系统级Introspector 缓冲中会保留这些类的hard引用。结果在你的web应用关闭的时候,这些类以及web 应用相关的class loader没有被垃圾收集器回收.
不幸的是,清除Introspector的唯一方式是刷新整个缓存。这是因为我们没法判断哪些是属于你的应用的引用.所以删除被缓冲的introspection会导致把这台server上的所有应用的introspection(内省)结果都删掉.
需要注意的是,spring容器托管的bean不需要使用这个监听器.因为spring它自己的introspection所使用的缓冲在分析完一个类之后会被马上从javaBeans Introspector缓冲中清除掉(上面提到的代码说明了这一点)。
一般的应用基本不会直接用到JavaBean的内省方法,所以一般不用考虑遇到此类内省资源泄露,但是,很多的类库或者框架(比如struts,Quartz)没有清除Introspector。这个Listener就是为它们“擦屁股”的。请注意,这个监听器需要注册在web.xml中的所有应用监听器之前(比如ContentLoaderListener之前)。
<listener>
<listener-class>
org.springframework.web.util.IntrospectorCleanupListener
</listener-class>
</listener>
分享到:
相关推荐
matplotlib-3.6.3-cp39-cp39-linux_armv7l.whl
numpy-2.0.1-cp39-cp39-linux_armv7l.whl
基于springboot个人公务员考试管理系统源码数据库文档.zip
onnxruntime-1.13.1-cp310-cp310-win_amd64.whl
基于springboot的西山区家政服务网站源码数据库文档.zip
Linux环境下,关于C++静态库的封装和调用代码。 TestLib是库目录。 TestLibCall是调用库的目录。
基于springboot软件技术交流平台源码数据库文档.zip
numpy-1.20.1-cp39-cp39-linux_armv7l.whl
ASP.NET酒店管理系统源码(WPF) 一、源码特点 采用WPF进行开发的酒店管理系统源码,界面相当美观,功能齐全 二、菜单功能 1、预订登记:可选择入住时间、离店时间、所在城市、证件类型,保存、删除、查询、返回 2、住宿结算:新增入住、保存、删除、查询、返回 3、今日盘点:查询、返回 4、查询统计: 5、房间管理:增加房间类型、删除类型、增加房间、删除房间、保存、返回 6、用户管理:增加用户、删除用户、保存、返回 7、系统配置:基本功能 8、显示当前系统时间等功能的实现
坠落的天空小游戏图片和代码
论文描述:该论文研究了某一特定领域的问题,并提出了新的解决方案。论文首先对问题进行了详细的分析和理解,并对已有的研究成果进行了综述。然后,论文提出了一种全新的解决方案,包括算法、模型或方法。在整个研究过程中,论文使用了合适的实验设计和数据集,并进行了充分的实验验证。最后,论文对解决方案的性能进行了全面的评估和分析,并提出了进一步的研究方向。 源码内容描述:该源码实现了论文中提出的新的解决方案。源码中包含了算法、模型或方法的具体实现代码,以及相关的数据预处理、实验设计和性能评估代码。源码中还包括了合适的注释和文档,以方便其他研究者理解和使用。源码的实现应该具有可读性、可维护性和高效性,并能够复现论文中的实验结果。此外,源码还应该尽可能具有通用性,以便在其他类似问题上进行进一步的应用和扩展。
环境说明: 开发语言:python Python版本:3.6.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:pycharm
基于springboot高校学术交流平台源码数据库文档.zip
onnxruntime-1.16.2-cp310-cp310-win_amd64.whl
基于springboot+vue的实践性教学系统源码数据库文档.zip
基于springboot的校园二手物品交易系统源码数据库文档.zip
numpy-1.23.5-cp39-cp39-linux_armv7l.whl
bimdata_api_client-4.0.2-py3-none-any.whl
环境说明: 开发语言:PHP 框架:原生php/thinkphp5 服务器:Apache 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat 11 运行软件:小皮phpStudy
基于SpringBoot的中老年人文化活动平台源码数据库文档.zip