Skip to content

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

@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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions