Для всех намерений и целей я считаю, что кэш вывода полностью находится в памяти - это означает, что если пул приложений будет перезагружен, образ необходимо будет сгенерировать заново.
Раньше мне приходилось делать нечто подобное, и я фактически реализовал двухуровневую систему, которая в основном использовала HTTP-кэш, и использовала файловую систему как запасной вариант. Если чего-то не было, я сгенерировал изображение, сохранил его на диске и поместил в кеш. Таким образом, если он выталкивается из кэша или пул приложений перезагружается, мне нужно только загрузить его с диска (кажется, вы сделали то же самое).
Что касается "слишком много памяти", если вы явно используете HttpContext.Cache вместо [OutputCache], вы можете контролировать приоритет элемента в кэше. Затем вы можете настроить параметры своего пула приложений, чтобы контролировать, сколько памяти он использует в целом, но я не уверен, что нужно сделать что-то еще, кроме этого. Пара изображений * 12 продуктов, похоже, не заняли бы у меня много памяти.
Не зная ничего о вашем приложении, для меня это звучит так, будто вы можете сойти с рук, просто используя выходной кэш. Однако, если вам нужно что-то более надежное и масштабируемое, я бы использовал двухуровневую систему, которую я описал. Хотя, если это уже реализовано и работает, «если оно не сломалось ...»