Потому что так работает подавляющее число скриптовых языков.
Когда нужна память - она берется из ОС. Когда память чистится, она помечается как доступная к перезаписи, но не отдается обратно ОС
Для такой задачи, как вы описали, следуте использовать фоновые очереди задач: delayed job, resque, sidekiq, rabbitmq...
Кстати, delayed job и, кажется, sidekiq - тоже не высвободят память. Их нужно будет убивать периодически убивать(например, с помощью monit и лимитом памяти). Resque же создает новый форк на каждую задачу