Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 903
Clayton Louden Avatar asked Oct 15 '12 21:10

Clayton Louden


1 Answers

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.

like image 109
garciap Avatar answered Oct 27 '22 20:10

garciap