Після виконання "m = new Window500" цей об'єкт буде висіти в пам'яті. Щоб збирач сміття зміг його вчасно видалити, отут радять ставити правильний Parent: https://stackoverflow.com/questions/14411154/a-wpf-window-doesnt-release-the-memory-after-closed Але це якщо у вас дуже проста юайка, без сторонніх компонентів. Бо сторонні компоненти запросто можуть тримати посилання на непотрібне вікно десь в своєму коді. Для виправлення таких проблем існують профілювальники, наприклад dotMemory або .Net Memory Profiler. У майкрософта також були якісь тулзи для цього.
Хоча усе це не гарантує нормального результату, якщо ваша програма має працювати 24/7. В таких випадках краще розділяти код, який має працювати постійно і юайку на окремі процеси. Тобто процес, який працює постійно, створює лише іконку в треї і просте меню, а коли треба показати решту юайки, то він запускає інший exe-файл.
На жаль, проблема з якою ви зіткнулися - це слабке місце усіх мов зі збирачем сміття. Виключенням є лише Swift, бо там збирач сміття не на основі алгоритму обходу дерева, а на основі підрахунку посилань. Відповідно у нього зовсім інші сильні та слабкі сторони.