Вызов метода ChannelFactory увеличивает память
У меня есть winform
приложение, которое использует службу Windows, я пользователь ChannelFactory
Чтобы подключиться к сервису, проблема заключается в том, что когда я вызываю метод сервиса с использованием канала, увеличивается использование памяти, а после выполнения метода не уменьшается память (даже после закрытия формы), я вызываю GC.Collect
но без изменений
канал Создать класс
public class Channel1
{
List<ChannelFactory> chanelList = new List<ChannelFactory>();
ISales salesObj;
public ISales Sales
{
get
{
if (salesObj == null)
{
ChannelFactory<ISales> saleschannel = new ChannelFactory<ISales>("SalesEndPoint");
chanelList.Add(saleschannel);
salesObj = saleschannel.CreateChannel();
}
return salesObj;
}
}
public void CloseAllChannels()
{
foreach (ChannelFactory chFac in chanelList)
{
chFac.Abort();
((IDisposable)chFac).Dispose();
}
salesObj = null;
}
}
базовый класс
public class Base:Form
{
public Channel1 channelService = new Channel1();
public Channel1 CHANNEL
{
get
{
return channelService;
}
}
}
класс winform
Form1:Base
private void btnView_Click(object sender, EventArgs e)
{
DataTable _dt = new DataTable();
try
{
gvAccounts.AutoGenerateColumns = false;
_dt = CHANNEL.Sales.GetDatatable();
gvAccounts.DataSource = _dt;
}
catch (Exception ex)
{
MessageBox.Show("Error Occurred while processing...\n" + ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
finally
{
CHANNEL.CloseAllChannels();
_dt.Dispose();
//GC.Collect();
}
}
1 ответ
Вы на правильном пути с точки зрения использования ChannelFactory<T>
, но ваша реализация немного отклонена.
ChannelFactory<T>
создает фабрику для генерации каналов типа T. Это относительно дорогая операция (по сравнению с простым созданием канала из существующей фабрики), и обычно выполняется один раз в течение жизни приложения (обычно при запуске). Затем вы можете использовать этот экземпляр фабрики, чтобы создать столько каналов, сколько нужно вашему приложению.
Как правило, после создания фабрики и ее кэширования, когда мне нужно позвонить в службу, я получаю канал от фабрики, выполняю звонок, а затем закрываю / отменяю канал.
Используя ваш отправленный код в качестве отправной точки, я бы сделал что-то вроде этого:
public class Channel1
{
ChannelFactory<ISales> salesChannel;
public ISales Sales
{
get
{
if (salesChannel == null)
{
salesChannel = new ChannelFactory<ISales>("SalesEndPoint");
}
return salesChannel.CreateChannel();
}
}
}
Обратите внимание, что я заменил salesObj
с salesChannel
(фабрика). Это создаст фабрику при первом вызове и каждый раз будет создавать новый канал с фабрики.
Если у вас нет особого требования, я не буду отслеживать различные каналы, особенно если придерживаюсь метода open/do /close.
В вашей форме это будет выглядеть примерно так:
private void btnView_Click(object sender, EventArgs e)
{
DataTable _dt = new DataTable();
try
{
gvAccounts.AutoGenerateColumns = false;
ISales client = CHANNEL.Sales
_dt = client.GetDatatable();
gvAccounts.DataSource = _dt;
((ICommunicationObject)client).Close();
}
catch (Exception ex)
{
((ICommunicationObject)client).Abort();
MessageBox.Show("Error Occurred while processing...\n" + ex.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
Приведенный выше код получает новый канал ISales от фабрики в CHANNEL, выполняет вызов, а затем закрывает канал. Если происходит исключение, канал прерывается в блоке catch.
Я бы не стал использовать Dispose()
из коробки на каналах, поскольку реализация в платформе имеет недостатки и выдаст ошибку, если канал находится в неисправном состоянии. Если вы действительно хотите использовать Dispose()
и заставить сборщик мусора, вы можете - но вам придется обойти проблему утилизации WCF. Google предложит вам несколько обходных путей (Google WCF использует для начала).