public void destroy() {
      if (destoyed) return;
      destoyed = true;
      
      try {
         // destroy resources
         Iterator it = windows.iterator();
         while(it.hasNext()) {
            Window w = (Window)it.next();
            if (w != null) w.dispose();
         }
         
         // interrupt all threads
         Thread threads[] = new Thread[ group.activeCount() * 2 ];
         int nthreads = group.enumerate(threads);
         for (int i=0; i < nthreads; i++) {
            //Skip AWT-EventQueue Threads
            if(threads[i].getName().startsWith("AWT-EventQueue")) {
               continue;
            }
            logger.log(Level.INFO, "Interrupt thread: "+threads[i]);
            threads[i].interrupt();
         }
         
         // then stop
         Thread.yield();
         nthreads = group.enumerate(threads);
         for (int i=0; i < nthreads; i++) {
            //Skip AWT-EventQueue Threads
            if(threads[i].getName().startsWith("AWT-EventQueue")) {
               continue;
            }
            logger.log(Level.INFO, "Stop thread: "+threads[i]);
            threads[i].stop();
         }
         
         //Signal classloader to destroy
         loader.destroy();
     }
     catch(Throwable t) {
        t.printStackTrace();
     }
     finally {
        loader = null;
        group = null;
        System.gc();
        logger.info("Free Memory:"+Runtime.getRuntime().freeMemory());
        logger.info("Total Memory:"+Runtime.getRuntime().totalMemory());
        long usedMemory = Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
        logger.info("Memory in Use:"+(usedMemory/1000000)+" megs");
     }
   }