JDK-7064279 : Introspector.getBeanInfo() should release some resources in timely manner
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 6u25
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2011-07-08
  • Updated: 2013-11-20
  • Resolved: 2011-12-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
6u29-revFixed 7u2Fixed 8 b17Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
A CU faces with memory leak. This seems to occur because Introspector.getBeanInfo()
does not release some resources.

JDK: 6u15(and later)/JDK7
OS : WindowsXP(SP3, Japanese)

The following source portion is extracted from JDK6u23.

The program accesses to AppContext at line#162.
If this access is the first time, AppContext.<clinit> starts to run.

 150     public static BeanInfo getBeanInfo(Class<?> beanClass)
 151         throws IntrospectionException
 152     {
 153         if (!ReflectUtil.isPackageAccessible(beanClass)) {
 154             return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
 155         }
 156         Map<Class<?>, BeanInfo> beanInfoCache;
 157         BeanInfo beanInfo;
 158         synchronized (BEANINFO_CACHE) {
 159             beanInfoCache = (Map<Class<?>, BeanInfo>) AppContext.getAppContext().get(BEANINFO_CACHE);
 160             if (beanInfoCache == null) {
 161                 beanInfoCache = new WeakHashMap<Class<?>, BeanInfo>();
 162                 AppContext.getAppContext().put(BEANINFO_CACHE, beanInfoCache);
 163             }
 164             beanInfo = beanInfoCache.get(beanClass);
 165         }
 166         if (beanInfo == null) {
 167             beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
 168             synchronized (BEANINFO_CACHE) {
 169                 beanInfoCache.put(beanClass, beanInfo);
 170             }
 171         }
 172         return beanInfo;
 173     }

In  AppContext.<clinit>, AppContext instance is created and the value of 
Thread.currentThread().getContextClassLoader() is set to the field of 
contextClassLoader at line#227.
The referent to the contextClassLoader never be broken.
That seems to result in memory leak.

221     AppContext(ThreadGroup threadGroup) {
222         numAppContexts++;
224         this.threadGroup = threadGroup;
225         threadGroup2appContext.put(threadGroup, this);
227         this.contextClassLoader =
228             (ClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
229                     public Object run() {
230                         return Thread.currentThread().getContextClassLoader();
231                     }
232                 });
233     }


A small program which simulates the above mentioned behavior.
Please unfoled the TP.zip and invoke "java Test" in jdk6ux.

If the referent is broken correctly, the message
"OK: MyClassLoader is not Reference."
appears and this is expected.

On tje other hands, in jdk6u15 and later,
"NG: MyClassLoader is Reference."
 will appear.
This shows that the referent still remains under the situation
when that should be broken.

In this test case, the impact is very small.
However, in actual applications like appli. servers, 
such small leak piles up for long application's run. 
That result in serious memory exhaustion.

Please see the comment section for a little bit more comment by the CU.

Verified in JDK8b116 Windows 7 Pro x64 Windows XP x32 Test output: cls.getClassLoader() = sun.misc.Launcher$AppClassLoader@15db9742 OK: MyClassLoader is not Reference

EVALUATION See comments.