В вашем вопросе есть один серьезный недостаток, который может быть причиной путаницы:
Кажется, что делегат и все будут помечены для сборки мусора после завершения Foo.
CLR не "помечает элементы" для сбора в конце процедуры. Скорее, когда эта процедура заканчивается, больше нет (активной) ссылки ни на один из элементов, на которые ссылается ваш делегат. В этот момент они называются «некорневыми».
Позже , когда CLR определяет, что существует определенная нагрузка на память, сборщик мусора будет выполняться. Он будет искать и находить все некорневые элементы и потенциально собирать их.
Важным отличием здесь является то, что время не может быть предсказано. Объекты могут никогда не собираться до тех пор, пока ваша программа не закончится, или они могут быть собраны сразу же. Система должна определить, когда она будет собираться. Этого не происходит, когда заканчивается Foo
- скорее, через какое-то неизвестное время после окончания Foo
.
Edit:
Это на самом деле напрямую касается вашего вопроса, кстати. Вы можете увидеть, если это проблема, форсировать сборку мусора. Просто добавьте после вашего звонка в Foo звонок на:
GC.Collect();
GC.WaitForPendingFinalizers();
Затем выполните проверку кучи CLR. На этом этапе, если вы все еще получаете объекты в куче, это потому, что объекты все еще чем-то укоренены. Ваш упрощенный пример не показывает, что это происходит, но так как это очень упрощенный пример, трудно определить, где это произойдет. (Примечание: я не рекомендую сохранять это в своем коде, если это так. Вызов GC.Collect () вручную почти всегда является плохой идеей ...)