简体   繁体   中英

Is my ThreadPoolExecutor leaking memory?

I'm using a ThreadPoolExecutor to run tasks. The backend is a SynchronousQueue , so if the executor is already perfoming a task, it throws the RejectedExecutionException . Here's a simple test case:

public class ExecutorTest {

  final static Worker worker = new Worker();

  public static void main(String[] args) {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());

    while (true) {
        try {                
            executor.execute(worker);                
        }catch (RejectedExecutionException e) {                
        }
    }        
  }

  static class Worker implements Runnable {

    private int i = 0;
    private long start = System.currentTimeMillis();

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
            System.out.println(++i + " " + (System.currentTimeMillis() - start));
        } catch (InterruptedException ex) {                
        }
    }
  }
}

The expected bahavious is: Execute the worker and after sleeping for a second, print out i (representing how often the worker has been executed so far) and the amount of milliseconds since the worker was created. So I'm expecting:

1 1015 
2 2015
3 3016 
4 4017

This works fine for a while, but after almost on hour:

2919 2922196
2920 2942951
2921 2990407

So the amount of time between one worker execution and the next one is 20 seconds (2919->2920) and 38 seconds (2920->2921) and so forth. Everything becomes extremely slow and the jvm spends a lot of time in garbage collection. Finally (after a few days) I run into an OutOfMemoryError.

I'm running this with -Xmx8M (I assume the effect appears much later with more heap space) on Oracle's JVM 1.7.0_07 on a 64bit Linux machine. I'd appreciate any pointers, but probably I'm just missing the obvious.

You can try to modify the ThreadPoolExecutor instantiation. You just have to add an argument to the constructor to use a RejectExecutionHandler that will silently discard rejected tasks.

public static void main(String[] args) {
  ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());

  while (true) {
    executor.execute(worker);                
  }
}

So if your problem comes from repeated RejectedExecutionException (and I think so), you will avoid it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM