For some reason, I was under the impression that jvisualvm(1) was just a rebranding of jconsole(1). It turns out that it isn't, and that – unlike jconsole(1) – it's not a waste of space.

It's not very clever about dividing up space between its various graphs, but other than that it looks pretty nice. I thought I wanted a quick heap profile to see why one of my applications ate so much memory that my machine always felt swappy afterwards. When jvisualvm(1) showed that there wasn't much heap retention going on, I was almost ready to dismiss it as broken, but thought I'd play about and see what else it could do. Turning to the "threads" tab, I saw my actual problem: I had several hundred idle threads.

It turned out I'd once again forgotten that "an unused ExecutorService should be shut down to allow reclamation of its resources".

I had code like this (only without the call to shutdown):

  ExecutorService service = Executors.newFixedThreadPool(threadCount);
  for (Input input : inputs) {
    service.execute(new Job(input));

Every time this ran, which was pretty frequently, I'd leak another 8 or so threads, that I'd never use again.

I should write myself some kind of "do this batch of jobs on n threads and then kill the threads" wrapper.

Anyway, although I was disappointed not to find any heap retention in any of my applications, I was quite pleased with jvisualvm(1) for finding a performance problem, even though it would have been as easy to spot with control-\ — I think that having all the tools together in one place makes me a bit more likely to bother to poke about now and again.

If you have trouble installing plugins like VisualGC, try quitting and restarting. I found that – contrary to the error message – they had actually installed okay, and appeared in the UI when I restarted. They even seem to work.


xargs -P

Another entry in my occasional series of options Unix never had when I were a lad (last time: tail -F)...

I needed to use xargs(1) the other day to run lots of really cheap jobs, each of which had a high latency.

This was taking a long time until a friendly youngster suggested I use GNU xargs' -P option. Starting again with -P 32, my job finished in less time than I'd already wasted.


Mac OS 10.6

I'm pleased to see Mac OS 10.6 is coming in September 2009, and I'm pleased it's going to be $29 instead of $129, because most Mac users I know stuck with 10.4 which was "good enough" and which they'd already paid for.

I'm slightly surprised by the "Mac computer with an Intel processor" requirement. At least I won't have to feel quite as bad about dropping PowerPC support myself.

I'm disappointed at the lack of detail about Java. "Complete Java JDK, including javac, javadoc, ANT, and Maven tools" doesn't tell me whether Java 6 will finally be the default, which is what I'm hoping for. PowerPC support doesn't cost me much (except the ability to build on 10.4 or 10.5 with the same make rules, which isn't a big problem as long as all the Mac OS-using developers are still on 10.4).

But being tied to Java 5 is increasingly annoying (and limiting). Reflection and other hacks only get you so far, and -source 1.5 doesn't protect you against accidentally using API that wasn't in Java 5 — String.isEmpty having caught me out just yesterday.