Lately we've found yet another memory leak in our applicaiton. It wasn't big - as it took almost about a week to fill 500MB heap, but still...
Now, after some searching I've found what this ScheduledTaskExecutor did. It scheduled timeout tasks for some jobs. They took longer or shorter time - but they all ended. And when they ended we called ScheduledFuture.cancel - to clean up executor:
So now we initialize our executors like this:
The culprit was not (entirely) on our side this time... Memory analyzer showed something more or less like this:
Now, after some searching I've found what this ScheduledTaskExecutor did. It scheduled timeout tasks for some jobs. They took longer or shorter time - but they all ended. And when they ended we called ScheduledFuture.cancel - to clean up executor:
ScheduledTask task = ...
task.cancel(true);
The problem was that some jobs have almost infinite timeout - like dating to year 3000. They all were canceled after few seconds but...
It turns out that with default settings it's not enough. Googling aroung wasn't very helpful, only after debugging I've found THE flag:
setRemoveOnCancelPolicy - defaults to false. Meaning that cancelled tasks do not get removed from executors internal queue. My first impression was WTF$%& - why is it false by default?? - but then I learned that the flag was added only in Java 7, so to maintain backwards compatibility...
So now we initialize our executors like this:
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.setRemoveOnCancelPolicy(true);