Счётчик ссылок в общем случае неприменим, т.к. не работает в случае с циклическими ссылками (два объекта держат друга друга - никому больше не нужны, но друг друга держат).

По поводу алгоритма ищем на слова "Mark & Sweep". Алгоритм классический ещё со времён появления Лиспа. Сначала проходим от корней (от глобальных указателей и указателей стека), помечая все пройденные. Затем проходим по списку выделенных блоков памяти, ища те, которые не помечены на предыдущей фазе - они, значит, недоступны, их удаляем.

В Явах/Шарпах навороченные модификации (с поколениями, алгоритм "поезд" и т.п. По поводу поколений есть в книге Рихтера про .NET). Оно себя не оправдывает.