Glassfish and its Memory Leaks

Glassfish is an widely used application server with full Java EE 6 support. One of the website's statements is: Well, decide for yourself, if that slogan is true.


Disclaimer

Note that bugs get fixed time by time and this page is not updated frequently.

More bugs filed

#Update-20140801

The matter here is the memory leak in glassfish on ear undeployment

If you are developing applications with glassfish you know what I'm talking about.
Have a look to the loaded classes after server start (having the ear deployed) and five successive deployments:
gf-memleak1.png gf-memleak2.png
You can clearly see the increasing count of loaded classes and how deployments are slowly eat your perm gen space.

Preview of the result

Tracking down the memory leaks

Once the glassfish is fixed, it looks like this:
gf-memleak3.png gf-memleak4.png

Tracking down the memory leaks

The plural is correct, it's more than one issue to find and eliminate. But where do you start? First you need some tools. Here is what I used:
  1. start the server with the no deployed ear.
  2. deploy the ear
  3. undeploy the ear
  4. force garbage collection
  5. search hard references to the dead EarClassLoader instance. In VisualVM you will use the context menu Show Nearest GC Root. But the this will only find the first path. Since there are hard references also paths via weak references will show up. So you have to deal with them too.

    There is a Dead Cow

    You found a hard reference? Remove it somehow:

Update-20140801

Here are some more bugs which need a fix: maybe it's easier to just patch the class org.omg.CORBA.ORB in the rt.jar? Source is provided and here is the modified method:
...
    private final static String NOARGS[] = {};
...
    public static synchronized ORB init() {
        if (singleton == null) {
            String className = getSystemProperty(ORBSingletonClassKey);
            if (className == null)
                className = getPropertyFromFile(ORBSingletonClassKey);
            if ((className == null) ||
                    (className.equals("com.sun.corba.se.impl.orb.ORBSingleton"))) {
                singleton = new com.sun.corba.se.impl.orb.ORBSingleton();
            } else {
                try {
                    singleton = create_impl_with_systemclassloader(className);
                } catch (RuntimeException re) {
                    singleton = init(NOARGS, null);
                }
            }
        }
        return singleton;
    } 



the helper methods getMember() and setMember()

    /**
     * Helper function to set a member of the given object.
     * 
     * @param reference
     *            the object to search for member
     * @param memberName
     *            the name of the member
     * @param value
     *            the value to set
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public void setMember(final Object reference, String memberName, Object value) throws NoSuchFieldException,
            IllegalAccessException {
        setMember(reference, reference.getClass(), memberName, value);
    }

    private void setMember(Object reference, Class<? extends Object> clazz, String memberName, Object value)
            throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        try {
            final Field field = clazz.getDeclaredField(memberName);
            field.setAccessible(true);
            field.set(reference, value);
        } catch (NoSuchFieldException nsfe) {
            if (clazz.getSuperclass() == null)
                throw nsfe;
            setMember(reference, clazz.getSuperclass(), memberName, value);
        }

    }

    /**
     * Helper function to get a member of the given object.
     * 
     * @param reference
     *            the object to search for member
     * @param memberName
     *            the name of the member
     * @return the object
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static Object getMember(Object reference, String memberName) {
        try {
            for (StringTokenizer st = new StringTokenizer(memberName, "."); st.hasMoreTokens();) {
                reference = getMember(reference, reference.getClass(), st.nextToken());
            }
            return reference;
        } catch (Exception ex) {
        }
        return null;
    }

    private static Object getMember(Object reference, Class<?> clazz, String memberName) throws NoSuchFieldException,
            IllegalAccessException {
        try {
            final Field memberField = clazz.getDeclaredField(memberName);
            memberField.setAccessible(true);
            final Object object = memberField.get(reference);
            return object;
        } catch (NoSuchFieldException nsfe) {
            if (clazz.getSuperclass() == null)
                throw nsfe;
            return getMember(reference, clazz.getSuperclass(), memberName);
        }
    }



Your job is now

Visit all open bugs and vote for them. This helps to get them fixed!
rev: 1.17