Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling @Push causes memory leak warnings on Atmosphere threads when Tomcat shuts down. #18077

Open
redsilver opened this issue Nov 20, 2023 · 2 comments

Comments

@redsilver
Copy link

Description of the bug

When I add @Push annotation on my AppShellConfigurator class I receive this warnings when stopping the webserver.
I also added asyncSupported = true in my servlet.

20-Nov-2023 15:25:56.533 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application appears to have started a thread named [Atmosphere-Scheduler-0] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.base@17.0.6/jdk.internal.misc.Unsafe.park(Native Method) java.base@17.0.6/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:252) java.base@17.0.6/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1672) java.base@17.0.6/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:1223) java.base@17.0.6/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:899) java.base@17.0.6/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1061) java.base@17.0.6/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1122) java.base@17.0.6/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) java.base@17.0.6/java.lang.Thread.run(Thread.java:833) 20-Nov-2023 15:25:56.533 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application appears to have started a thread named [Atmosphere-Scheduler-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.base@17.0.6/jdk.internal.misc.Unsafe.park(Native Method) java.base@17.0.6/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:252) java.base@17.0.6/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1672) java.base@17.0.6/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:1218) java.base@17.0.6/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.poll(ScheduledThreadPoolExecutor.java:899) java.base@17.0.6/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1061) java.base@17.0.6/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1122) java.base@17.0.6/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) java.base@17.0.6/java.lang.Thread.run(Thread.java:833) 20-Nov-2023 15:25:56.533 WARNING [main] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application appears to have started a thread named [Atmosphere-Shared-0] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.base@17.0.6/jdk.internal.misc.Unsafe.park(Native Method) java.base@17.0.6/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:252) java.base@17.0.6/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:1672) java.base@17.0.6/java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:460) org.atmosphere.cpr.DefaultBroadcaster$1.run(DefaultBroadcaster.java:405) java.base@17.0.6/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) java.base@17.0.6/java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:264) java.base@17.0.6/java.util.concurrent.FutureTask.run(FutureTask.java) java.base@17.0.6/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1395) java.base@17.0.6/java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:373) java.base@17.0.6/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java) java.base@17.0.6/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182) java.base@17.0.6/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655) java.base@17.0.6/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622) java.base@17.0.6/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165) 20-Nov-2023 15:25:56.537 INFO [main] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-8080"] 20-Nov-2023 15:25:56.549 INFO [main] org.apache.coyote.AbstractProtocol.destroy Destroying ProtocolHandler ["http-nio-8080"]

Expected behavior

No warning logs appears when i stop the Tomcat.

Minimal reproducible example

Simply add @Push in AppShellConfigurator class

Versions

  • Vaadin / Flow version: 24.2.2, 24.2.3
  • Java version: jbr17.0.6 (i tried also corretto 17.0.4)
  • OS version: OSX 14.1.1
  • Application Server: i tried Tomcat 10.1.8 and 10.1.15
  • IDE: IntelliJ Ultimate 2023.2.5
@redsilver redsilver changed the title Enabling @Push causes memory leak warnings on Atmosphere threads on webserver's shutdown. Enabling @Push causes memory leak warnings on Atmosphere threads when Tomcat shuts down. Nov 20, 2023
@mshabarov
Copy link
Contributor

Same warning as described here #17731.

@tltv
Copy link
Member

tltv commented Nov 23, 2023

[Atmosphere-Shared-0] and [Atmosphere-Scheduler-0] and [Atmosphere-Scheduler-1] refer to threads started by Atmosphere Framework's org.atmosphere.util.ExecutorsFactory which is needed when Push is enabled.

Warnings are generated by Tomcat when it shuts down, but it doesn't know that ExecutorFactory is running threads that may need more time to be destroyed, they will be cleaned up eventually (afaik default timeout is 30 seconds). Warnings are not actually causing memory leaks, they are just annoying in this case. Therefore I don't see reason for Flow to do anything different.

Warning might not go away however even if Spring boot app shutdown waits for that 30 seconds. That's because Atmosphere-Scheduler will spawn new thread when old one is destroyed.

I got rid of the warnings with the following solution for skeleton-starter-flow-spring Spring application by shutting down thread executors explicitly in a ServletContextListener in following way:

Application.java

package org.vaadin.example;

@ServletComponentScan
@SpringBootApplication
...
@Push
public class Application implements AppShellConfigurator {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

ExampleServletContextListener .java

package org.vaadin.example;

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.annotation.WebListener;

import java.util.concurrent.ExecutorService;

import org.atmosphere.cpr.AtmosphereFramework;
import org.atmosphere.util.ExecutorsFactory;

import com.vaadin.flow.server.communication.JSR356WebsocketInitializer;

@WebListener
public class ExampleServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(
            ServletContextEvent sce) {
        // Context Initialised
    }

    @Override
    public void contextDestroyed(
            ServletContextEvent event) {
        // notice that this example iterates through all servlet registrations, it may need filtering
        event.getServletContext()
                .getServletRegistrations().values().forEach(value -> {
                    AtmosphereFramework framework = readAtmosphereFramework(value, event);
                    shutdownAtmosphereExecutorService(framework, ExecutorsFactory.SCHEDULER_THREAD_POOL);
                    shutdownAtmosphereExecutorService(framework, ExecutorsFactory.BROADCASTER_THREAD_POOL);
                });
        System.out.println("Servlet Context Destroyed");
    }

    private void shutdownAtmosphereExecutorService(AtmosphereFramework framework, String property) {
        if (framework != null) {
            ExecutorService e = (ExecutorService) framework.getAtmosphereConfig().properties().get(property);
            if (e != null) {
                e.shutdownNow();
                System.out.println("Shutdown Atmosphere " + property);
            }
        }
    }

    private AtmosphereFramework readAtmosphereFramework(ServletRegistration reg, ServletContextEvent ev) {
        String attributeName = JSR356WebsocketInitializer
                .getAttributeName(reg.getName());
        Object framework = ev.getServletContext()
                .getAttribute(attributeName);
        if (framework instanceof AtmosphereFramework) {
            return (AtmosphereFramework) framework;
        }
        return null;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 🔖 Normal Priority (P2)
Status: 🪵Product backlog
Development

No branches or pull requests

3 participants