Александр, спасибо за поучительный рассказ!

По поводу определения, когда объект больше не показывается на экране... Здесь можно пойти таким путем - через модуль Windows искать открытые кадры, связанные с отображением. Если их нет, то можно останавливаться...

Я тоже сталкивался с проблемой регистрации объектов в глобальных списках. Зарегистрировав объект в списке, мы создаем на него глобальный якорь. Но таким образом список не может узнать сам, когда объект более не нужен! N-е время назад я написал процедурку, которая позволяет искать на низком уровне все ссылки на объект (как это делает Kernel.Mark) и сделал в модуле-регистраторе некий высокоуровневый сборщик мусора, который периодически проверял, остались ли на объекты внешние ссылки, и если нет, то исключал их из списка - а далее их "добивал" обычный сборщик
Сейчас, переписывая рантайм, я позаимствовал одну хорошую идею, которая есть в .NET - слабые указатели (weak pointers). Слабый указатель - это ссылка на объект, которая не является якорем. Когда нам нужно работать с объектом, мы можем запросить у слабого указателя обычный указатель. Если нам вернут NIL, то мы видим, что объект уже собран сборщиком мусора.

А вообще, с многопоточностью все равно работать гораздо лучше, нежели без нее