[visad] finally solved Visad offscreen mode memory problems

I have mostly tried to use visad for offscreen rendering, from servlets in
web apps. The intention was

DisplayImpl di = new DisplayImplJ2D( "", w, h );
BufferedImage bi = di.getImage(true);
di.destroy();

As you would expect, we want the net memory footprint of the above
sequence to be just the BufferedImage, which we can save to disk or use a
servlet to serialize to some web client.  Thus the net footprint is then
zero.  This is vital in a long lived app like a web site.

I have always had problems, frequently exhausting memory.  I should point
out that I am trying to render some large images, on the order of 6000 x
6000, but really that is beside the point, it just makes the outofmemory
occur earlier.

Finally, after about 3 years of looking at this, I think have a solution. 
It now seems obvious why it was failing at all.

In VisADCanvasJ2D, we have

stop() {
  renderThread =null;
}

and

run() {
  while ( renderThread != null ) {
    do some work;
    wait for more work;
}

The problem is that the stop code is not powerful enough to halt the run
code.  At any given point in time, the run code (the renderThread) can be
anywhere in its loop.  If it is in wait, it will stay there forever.  The
thread is live, thus the canvas it references (the Runnable) is also, and
so are any BufferedImages we have built.  we cannot GC any of it.


We need to raise an interrupt in this thread.  This will get us out of a
wait call, if the interrupt is posted either before or during the wait.  I
think the soln is this

volatile boolean done = false;

stop () {
  done = true;
  renderThread.interrupt();
  renderThread.join();
}

run() {
  while( !done ) {
    try {
      do some work;
       wait;
    } catch( InterruptedException ie ) {
    }
  }
}

This makes the calling program , which calls stop via the
DisplayImpl.destroy(), wait for the renderThread to finish.  We need the
boolean done, we cannot do this from stop:

renderThread.interrupt();
renderThread = null;

since the run could get the interrupt, test the renderThread for non null
and do another wait, all before the stop can set the renderThread to null
( i have tested this and seen it occur).

Initially i coded the joining of the calling (application) thread and
renderThread using a CountdownLatch set to 1, from java.util.concurrent,
with stop doing a latch.await() and run doing a latch.countDown() as its
final action, but the thread join seems equivalent to that (anyone??).

One caveat of raising the interrupt on the renderThread is that somewhere
in the 'do some work' the newly raised interrupt can lead to an abort of
the work.  But we dont really care, since we have got our image via
getImage and then called destroy in that order.

I hope this helps anyone trying to use Visad in offscreen mode,
particularly in webapps.

Comments welcomed.

Stuart




  • 2007 messages navigation, sorted by:
    1. Thread
    2. Subject
    3. Author
    4. Date
    5. ↑ Table Of Contents
  • Search the visad archives: