Skip to content

MemoryAllocationExports Not Collected By Garbage Collector And Causing Metaspace OutOfMemoryException #809

Open
@Drophoff

Description

@Drophoff

Actual Situation

The class MemoryAllocationExports creates a memory leak caused by AllocationCountingNotificationListener that is added but never removed, when this libary is included within a WAR application that gets deployed on a Tomcat server.

The AllocationCountingNotificationListener is added to the class GarbageCollectorMXBean (see class GarbageCollectorExtIml at the attached screenshot) that is loaded by java.lang.ClassLoader, which is different from the org.apache.catalina.loader.ParallelWebappClassLoader.

  public MemoryAllocationExports() {
    AllocationCountingNotificationListener listener = new AllocationCountingNotificationListener(allocatedCounter);
    for (GarbageCollectorMXBean garbageCollectorMXBean : getGarbageCollectorMXBeans()) {
      if (garbageCollectorMXBean instanceof NotificationEmitter) {
        ((NotificationEmitter) garbageCollectorMXBean).addNotificationListener(listener, null, null);
      }
    }
  }

Because of this the AllocationCountingNotificationListener has a reference to a class with a different classloader, which prevents that this class gets collected by garbage collector.

ClassLoaderReferences

Possible solution (outlook)

At the moment the class MemoryAllocationExports provides no function to retrieve a instance of AllocationCountingNotificationListener, which is needed to call NotificationEmitter#removeNotificationListener:

  for (GarbageCollectorMXBean garbageCollectorMXBean : getGarbageCollectorMXBeans()) {
	  if (garbageCollectorMXBean instanceof NotificationEmitter) {
		((NotificationEmitter) garbageCollectorMXBean).removeNotificationListener(listener);
	  }
  }

When the above code gets called the class is collected and clean up by the garbage collector.

The class DefaultExports contains already a function for initialization. Possibly this class would also be suitable to provide a corresponding function for the clean shutdown, which could be called during ServletContextListener#contextDestroyed.

Environment

  • Server: Apache Tomcat 9.0.65
  • JVM: 17.0.4.1+1 Eclipse Adoptium
  • OS: Linux 4.19.0-13-amd64
  • Simpleclient Version: 0.16.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions