В общем случае — никак. А зачем? Единственная возможная рекомендация здесь — пишите код так, чтобы много памяти не тратилось.
Гипотетически, можно разработать для приложения специальную архитектуру, которая будет позволять прерывать любые запущенные задачи при превышении порога памяти, освобождать ресурсы и затем дожидаться вызова GC. Например, через TPL с CancellationToken. Но это, мягко говоря, непростой путь. Занимаемую память можно мониторить через GC.GetTotalMemory или средствами ОС. Но есть ещё два нюанса:
1. Постоянное измерение памяти приведет к падению общей производительности программы
2. Вы не сможете использовать библиотеки, которые не поддерживают отмену вызванных функций