У меня есть консольное приложение для Windows, которое должно работать без перезапуска в течение нескольких дней и месяцев. Приложение извлекает «работу» из MSMQ и обрабатывает ее. Есть 30 потоков, которые обрабатывают рабочий фрагмент одновременно.
Каждый рабочий фрагмент, поступающий из MSMQ, составляет примерно 200 КБ, большая часть которых выделяется в одном объекте String.
Я заметил, что после обработки примерно 3–4 тысяч этих рабочих блоков потребление памяти приложением невероятно велико, занимая 1–1,5 ГБ памяти.
Я запустил приложение через профилировщик и заметил, что большая часть этой памяти (возможно, гигабайт или около того) не используется в куче больших объектов, но структура фрагментирована.
Я обнаружил, что 90% этих неиспользуемых (собранных в мусор) байтов были ранее выделены String. Тогда я начал подозревать, что строки, поступающие из MSMQ, были выделены, использованы, а затем освобождены и, следовательно, являются причиной фрагментации.
Я понимаю, что такие вещи, как GC.Collect (2 или GC.Max ...), не помогут, так как они собирают кучу больших объектов, но не сжимают ее (вот в чем проблема). Поэтому я думаю, что мне нужно кэшировать эти строки и как-то повторно использовать их, но поскольку строки неизменяемы, мне пришлось бы использовать StringBuilders.
Мой вопрос: есть ли способ не изменить базовую структуру (т.е.используя MSMQ, так как это то, что я не могу изменить) и по-прежнему избегать инициализации новой строки каждый раз, чтобы избежать фрагментации LOH?
Спасибо, Яннис
ОБНОВЛЕНИЕ: О том, как эти "рабочие" блоки в настоящее время извлечено
В настоящее время они хранятся как объекты WorkChunk в MSMQ. Каждый из этих объектов содержит строку с именем Contents и другую строку с именем Headers. Это актуальные текстовые данные. Я могу изменить структуру хранения на что-то другое, если необходимо, и, возможно, базовый механизм хранения, если необходимо, на что-то еще, кроме MSMQ.
На стороне рабочих узлов в настоящее время мы выполняем
WorkChunk chunk = _Queue.Receive ();
Таким образом, на этом этапе мы мало что можем кэшировать. Если бы мы как-то изменили структуру (-ы), я полагаю, мы могли бы добиться небольшого прогресса. В любом случае нам придется разобраться с этой проблемой, чтобы мы сделали все необходимое, чтобы не тратить месяцы работы.
ОБНОВЛЕНИЕ: Я попробовал некоторые из приведенных ниже предложений и заметил, что эта проблема не может быть воспроизведена на моем локальном компьютере (под управлением Windows 7 x64 и 64-битного приложения). это значительно усложняет задачу - если кто-нибудь знает, почему, тогда это действительно поможет перепрограммировать эту проблему локально.