sbool cleanUp_interruptThreads; // experimental static void cleanUp(O c) { if (c == null) ret; if (c instanceof Collection) { cleanUp((Collection) c); ret; } if (c instanceof Map) { for (O o : keys((Map) c)) cleanUp(o); for (O o : values((Map) c)) cleanUp(o); ((Map) c).clear(); ret; } //if (!(c instanceof Class)) ret; pcall { // revoke license callOpt(c, 'licensed_off); setOpt(c, cleaningUp_flag := true); // unpause setOpt(c, "ping_pauseAll", false); // call custom cleanMeUp() and cleanMeUp_*() functions innerCleanUp(c); // Java spec says finalize should only be called by GC, // but we care to differ. pcallOpt(c, "finalize"); // remove all virtual bots (hope this works) L androids = (L) getOpt(c, "record_list"); for (O android : unnull(androids)) pcallOpt(android, "dispose"); // heck we'll dispose anything // sub-cleanup L classes = cast getOpt(c, "hotwire_classes"); if (classes != null) for (WeakReference cc : classes) pcall { cleanUp(cc.get()); } // interrupt all threads (experimental, they might be doing cleanup?) if (cleanUp_interruptThreads) { L threads = registeredThreads(c); print("cleanUp: Interrupting " + n2(thread, "thread")); interruptThreads(threads); } } setOpt(c, cleaningUp_flag := false); if (c instanceof Class && ((Class) c).getName().equals("main")) retireClassLoader(((Class) c).getClassLoader()); } static void cleanUp(Collection l) { if (l == null) ret; for (O c : l) cleanUp(c); l.clear(); }