17

我有一个 Web 应用程序(使用 Spring 3.1),它使用 @Scheduled Annotation 定期执行工作任务(计划延迟)。工作任务打开与 AWS DynamoDb 的连接并执行一些数据库读取/更新。当我停止 webapp(来自 Tomcat 管理器)时,我在 catalina.out 中收到此消息:

“严重:Web 应用程序 [] 似乎已经启动了一个名为 [java-sdk-http-connection-reaper] 的线程,但未能阻止它。这很可能会造成内存泄漏。”

我感觉这与我的计划任务在 Tomcat 停止后仍在运行有关。

@Service
public class TaskScheduler implements ApplicationListener<ContextClosedEvent>{

@Autowired
private WorkerTask workerTask;

AmazonDynamoDBClient myDbConn = null;

   private TaskScheduler() {    
   myDbConn = new AWSConnector("aws.properties").getDynamoConnection();
   }

/*
 * Will be repeatedly called, 10 seconds after the finish of the previous 
 * invocation.
 */
@Scheduled(fixedDelay=100000)
public void process() {
    System.out.println("Scheduling worker task");
            //worker task does some db read/writes
    Future<String> status = workerTask.work(myDbConn);
    if (status.isDone()) {
        System.out.println("Completed Task");
        return;
    }

}

@Override
public void onApplicationEvent(ContextClosedEvent arg0) {
    if(event instanceof ContextClosedEvent) {   
      // TODO Auto-generated method stub
      if(myDbConn != null) {
        this.myDbConn.shutdown();
      }
          }

}

调度程序-servlet.xml:

<task:annotation-driven scheduler="taskScheduler"/>
<task:scheduler id="taskScheduler" pool-size="2"/>
......
<bean id="TaskScheduler" class="com.sample.TaskScheduler"/>

Am I doing this correctly? a) I don't explicitly start the TaskScheduler. So i'm assuming spring takes care of starting this service. The 'this.myDbConn.shutdown()' is called. Despite this, I get the error. I'm using Spring MVC.

4

3 回答 3

17

This is likely caused by the AWS library which starts a thread in the background called com.amazonaws.http.IdleConnectionReaper

You can shut it down by implementing a ServletContextListener to close it on shutdown

public class YourListener implements ServletContextListener {

@Override
public void contextInitialized(ServletContextEvent contextEvent) {

}

@Override
public void contextDestroyed(ServletContextEvent contextEvent) {

    try {
        com.amazonaws.http.IdleConnectionReaper.shutdown();
    } catch (Throwable t) {
        // log the error
    }
}
}

and adding this to your web.xml

<listener>
    <listener-class>
        your.package.YourListener 
    </listener-class>
</listener>
于 2013-10-09T22:20:15.523 回答
9

我也遇到了这个问题,但我决定采用上述@David_Wartell 的替代解决方案。

我从亚马逊的 aws-java-sdk 库中找到了创建有问题的对象/对象的类,这些对象正在启动 IdleConnectionReaper 线程但从未关闭(这些是com.amazonaws.services.ec2.AmazonEC2Client和 com.amazonaws.services .cloudwatch.AmazonCloudWatchClient _)。然后我在这个类中添加了一个 destroy() 方法,它调用了静态方法 com.amazonaws.http.IdleConnectionReaper.shutdown()。当类被垃圾收集并使用 Spring applicationContext.xml 配置时,将调用 destroy 方法。这样做的好处是它甚至可以用于非 Web 应用程序,并且它可以将线程关闭与您的 Web 上下文分离。正确的解决方案是启动 IdleConnectionReaper 线程的 amazon aws-java-sdk 库中的类应该关闭它,但它们不会 - 因此出现这个错误。有关我的解决方案,请参阅下面的参考资料和代码片段:

应用程序上下文.xml

<bean id="YourBeanName" class="com.your.package.name.YourBeanName" destroy-method="destroy">
    <!-- other optional configuration goes here -->
</bean>

YourBeanName.java -(创建有问题的亚马逊对象的类)

    public class YourBeanName {

        // omitted code

        public void destroy() {
            com.amazonaws.http.IdleConnectionReaper.shutdown();
        }

        // omitted code

    }

参考:

Amazon 论坛 - 关闭 IdleConnectionReaper
Spring 文档 - 自定义 bean 的性质

于 2013-12-17T11:30:48.150 回答
4

在 Stuart 的回答之上(假设您使用的是 Spring),如果您不使用 XML 配置文件,则另一种选择:

@Component
public class MyBean {

// ...

    @PreDestroy
    private void cleanUp() {
        try {
            // Shutting down AWS IdleConnectionReaper thread...
            com.amazonaws.http.IdleConnectionReaper.shutdown();
        } catch (Throwable t) {
            // log error
        }
    }

}

当我使用实现com.amazonaws.services.s3.AmazonS3接口的 bean 时,它对我有用。

于 2014-08-28T14:43:16.607 回答