@ Евгений, какой тип управления сервисами вы используете?

зируя клиентское приложение WCF (о котором я не писал и до сих пор не знаю слишком много), которое общается с кучей сервисов через SOAP и после запуска в течение нескольких дней выдает исключение OutOfMemoryException, я обнаружил, что .net PooledBufferManager будет никогда не освобождайте неиспользуемые буферы, даже если приложению не хватает памяти, что приводит к OOME.

Это, конечно, в соответствии со спецификацией:http://msdn.microsoft.com/en-us/library/ms405814.aspx

Пул и его буферы [...] уничтожаются, когда пул буферов освобождается сборщиком мусора.

Пожалуйста, не стесняйтесь отвечать только на один из приведенных ниже вопросов, поскольку у меня есть несколько вопросов, некоторые из которых носят более общий характер, а некоторые специфичны для использования нашим приложением BufferManager.

Сначала пара общих вопросов о (по умолчанию Pooled) BufferManager:

1) В среде, где у нас есть GC, зачем нам нужен BufferManager, который будет удерживать неиспользуемую память, даже если это приводит к OOME? Я знаю, что есть BufferManager.Clear (), который вы можете использовать длявручную избавиться от всех буферов - если у вас есть доступ к BufferManager, то есть. Посмотрите дальше, почему у меня нет доступа.

2) Несмотря на заявления MS о том, что «этот процесс намного быстрее, чем создание и уничтожение буфера каждый раз, когда вам нужно его использовать», не следует ли оставить это на усмотрение GC (и его LOH, например), и вместо этого оптимизировать GC ?

3) При выполнении BufferManager.Take (33 * 1024 * 1024) я получу буфер размером 64 МБ, поскольку PooledBufferManager будет кешировать этот буфер для последующего повторного использования, что, возможно, в моем случае не так, и поэтому это чистая трата памяти - будь то, скажем, 34M, или 50M, или 64M, необходимы. Так было ли разумно создать потенциально очень расточительный BufferManager, подобный этому, который используется (по умолчанию, я полагаю) HttpsChannelFactory? Мне не удается понять, как важна производительность для выделения памяти, особенно когда мы говорим о WCF и сетевых сервисах, с которыми приложение будет обращаться к TOPS каждые 10 секунд, обычно много секунд или даже минут.

Теперь некоторые более конкретные вопросы, связанные с использованием нашего приложения BufferManager. Приложение подключается к паре разных служб WCF. Для каждого из них мы поддерживаем пул соединений для http-соединений, так как соединения могут происходить одновременно.

Проверка самого большого объекта в одном дампе кучи, массива в 64 Мб, который использовался только один раз в нашем приложении во время инициализации и впоследствии не нужен, поскольку ответ от службы настолько велик только во время инициализации, что, кстати. это типично для многих примененных ионов, которые я использовал, хотя это может быть предметом оптимизации (кэширование на диск и т. д.). Анализ корня GC в WinDbg приводит к следующему (я очистил имена наших проприетарных классов до «MyServiceX» и т. Д.):

0:000:x86> !gcroot -nostacks 193e1000
DOMAIN(00B8CCD0):HANDLE(Pinned):4d1330:Root:0e5b9c50(System.Object[])->
035064f0(MyServiceManager)->
0382191c(MyHttpConnectionPool`1[[MyServiceX, MyLib]])->
03821988(System.Collections.Generic.Queue`1[[MyServiceX, MyLib]])->
038219a8(System.Object[])->
039c05b4(System.Runtime.Remoting.Proxies.__TransparentProxy)->
039c0578(System.ServiceModel.Channels.ServiceChannelProxy)->
039c0494(System.ServiceModel.Channels.ServiceChannel)->
039bee30(System.ServiceModel.Channels.ServiceChannelFactory+ServiceChannelFactoryOverRequest)->
039beea4(System.ServiceModel.Channels.HttpsChannelFactory)->
039bf2c0(System.ServiceModel.Channels.BufferManager+PooledBufferManager)->
039c02f4(System.Object[])->
039bff24(System.ServiceModel.Channels.BufferManager+PooledBufferManager+BufferPool)->
039bff44(System.ServiceModel.SynchronizedPool`1[[System.Byte[], mscorlib]])->
039bffa0(System.ServiceModel.SynchronizedPool`1+GlobalPool[[System.Byte[], mscorlib]])->
039bffb0(System.Collections.Generic.Stack`1[[System.Byte[], mscorlib]])->
12bda2bc(System.Byte[][])->
193e1000(System.Byte[])

Просмотр корней gc для других байтовых массивов, управляемых BufferManager, показывает, что другие сервисы (не MyServiceX) имеют разные экземпляры BufferPool, поэтому каждый из них тратит свою собственную память, они даже не разделяют потери.

4) Мы что-то здесь не так делаем? Я ни в коем случае не эксперт WCF, поэтому можем ли мы заставить различные экземпляры HttpsChannelFactory использовать один и тот же BufferManager?

5) Или, может быть, даже лучше, можем ли мы просто сказать всем экземплярам HttpsChannelFactory НЕ использовать BufferManager вообще и попросить GC выполнить свою чертову работу, которая заключается в «управлении памятью»?

6) Если на вопросы 4) и 5) невозможно ответить, могу ли я получить доступ к BufferManager всех экземпляров HttpsChannelFactory и вручную вызвать .Clear () для них - это далеко не оптимальное решение, но это уже поможет, в моем В этом случае освободятся не только упомянутые выше 64M, но и 64M + 32M + 16M + 8M + 4M + 2M только в одном экземпляре службы! Так что это само по себе сделало бы мое приложение более продолжительным без проблем с памятью (и нет, у нас нет проблемы утечки памяти, кроме BufferManager, хотя мы действительно потребляем много памяти и накапливаем много данных в течение курса много дней, но это не проблема здесь)

Ответы на вопрос(3)

Ваш ответ на вопрос