I have a problem. I have coded a wcf client (WPF and c#) that is using wsHttpBinding.
And I´m using duplex. I have a function that i call the wcf service every minute called KeepConnection.
And i never close the client proxy because i need to have the client “online” all the time for service callbacks. But when running this client on Windows XP i have a strange problem with the memory of my application.When running normally on win 7 /vista the application only uses 40mb of memory in taskmanger. In Xp in constantly increase the use of memory every second.
I got over 700mb on 2 days.
Is there a way to fix this or is it XP related. Thanks for help.
Service code:
/// <summary>
/// Just an empty method for client to keep the connection alive with the service.
/// </summary>
public void KeepConnection()
{
_logger.Debug("Keep alive requested.");
}
My client code.
private InstanceContext instanceContext; //Wcf instance context for callbacks.
public static BootDialog _bootScreen = new BootDialog(); //Boot window.
public static RetryDialog _retryScreen = new RetryDialog(); //Retry window.
public static ProductionServiceClient service; //Wcf service client
public static ClientCallBack clientBack; //Client callback events and handler.
public static ClientTokenResponse ClientToken; //ClientToken from wcf service.
public static int[] ScannerNumbers;
public static IList<HighlightArticleDto> highListArticleList; //List and color of witch list to highligt.
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
private static ClientTokenRequest clientRequest;
private Timer _keepAliveTimer = new Timer();
private void Application_Startup(object sender, StartupEventArgs e)
{
_logger.Trace("Enter Application_Startup().");
int[] scannerNumberList = ParseHandler.GetScannersFromSettingString(Settings.Default.Scanners);
//Saves it globally
App.ScannerNumbers = scannerNumberList;
_logger.Info("Getting {0} scanners for this client.", scannerNumberList.Count());
clientBack = new ClientCallBack();
instanceContext = new InstanceContext(clientBack);
//ToDO : This fix is for XP computer with the http://+:80/Temporary_Listen_Addresses/c269764e-808e-4284-ad7f-4e0eb88ee951/ error.
WSDualHttpBinding binding = new WSDualHttpBinding();
binding.Name = "WsDualTcpEndpoint";
binding.CloseTimeout = new TimeSpan(0, 0, 10);
binding.OpenTimeout = new TimeSpan(0, 0, 10);
//binding.ReceiveTimeout = new TimeSpan(0, 0, 30);
binding.SendTimeout = new TimeSpan(0, 0, 10);
binding.BypassProxyOnLocal = false;
binding.TransactionFlow = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 65536;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.UseDefaultWebProxy = false;
binding.Security.Mode = WSDualHttpSecurityMode.None;
StringBuilder sb = new StringBuilder();
sb.Append("http://").Append(GetLocalIp()).Append(":808/WSDualOnXP");
_logger.Debug("Client base address : {1}.", sb.ToString());
binding.ClientBaseAddress = new Uri(sb.ToString());
EndpointAddress endpoint = new EndpointAddress(Settings.Default.ServerAddress);
service = new ProductionServiceClient(instanceContext, binding, endpoint);
//2011-08-25 Test utav clientbase
//service = new ProductionServiceClient(instanceContext, "WsDualTcpEndpoint", Settings.Default.ServerAddress);
_logger.Debug("Server address : {0}.", Settings.Default.ServerAddress);
//ToDo Disabled GeneralDialog.
//2011-05-25 Remove this comment if generaldialog wants to be seen.
//if (scannerNumberList.Count() == 0 || String.IsNullOrEmpty(Settings.Default.ServerAddress))
//{
// GeneralDialog dialog = new GeneralDialog();
// dialog.Show();
// return;
//}
//Subscribe to wcf service.
SubscribeToService(scannerNumberList);
//Keep connection to the service alive.
KeepAlive();
//Start timer for highlight list
GetHighLightListTimer();
//Catch unhandled exceptions
this.DispatcherUnhandledException += new System.Windows.Threading.DispatcherUnhandledExceptionEventHandler(App_DispatcherUnhandledException);
}
private void KeepAlive()
{
_keepAliveTimer.Interval = 31000;
_keepAliveTimer.Elapsed +=
(
(object o, ElapsedEventArgs args) =>
{
try
{
_keepAliveTimer.Stop();
if (service.State != CommunicationState.Opened)
{
if (service != null) { service.Abort(); }
ShowRetryDialog();
RetryToSubscribe();
}
service.KeepConnection();
}
catch (TimeoutException ex)
{
if (service != null) { service.Abort(); }
ShowRetryDialog();
RetryToSubscribe();
}
catch (CommunicationException ex)
{
if (service.State != CommunicationState.Opened)
{
if (service != null) { service.Abort(); }
ShowRetryDialog();
RetryToSubscribe();
}
}
catch
{
if (service != null) { service.Abort(); }
_keepAliveTimer.Stop();
ShowRetryDialog();
RetryToSubscribe();
}
finally
{
_keepAliveTimer.Start();
}
}
);
_keepAliveTimer.Start();
}
And My client Callbacks.
#region ClientCallBacks
//When service callbacks to the client this methods will be triggered.
void clientBack_ClientNotified(object sender, ClientNotifiedEventArgs e)
{
throw new NotImplementedException();
}
void clientBack_RemoveFromDisplayEvent(object sender, RemoveFromDisplayEventArgs e)
{
try
{
_logger.Info("Remove from display.");
userControlChairs.Dispatcher.Invoke((Action)(() =>
{
_queueProductionItems.Remove(e.OrderResponse);
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void clientBack_AddToDisplayEvent(object sender, AddToDisplayEventArgs e)
{
try
{
_logger.Info("Add to display.");
userControlChairs.Dispatcher.Invoke((Action)(() =>
{
_queueProductionItems.Add(e.OrderResponse);
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
void clientBack_UpdateQueueDisplayEvent(object sender, UpdateQueueDisplayEventArgs e)
{
try
{
_logger.Info("Update queue display.");
userControlQueue.Dispatcher.Invoke((Action)(() =>
{
_queueDisplayItems.Clear();
foreach (OrderDto o in e.UnfinishedOrdersResponse.Orders)
{
_queueDisplayItems.Add(o);
}
}));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#endregion
private ObservableOrderResponseQueue _queueProductionItems = new ObservableOrderResponseQueue(); //List of the chairs that will be displayed.
private ObservableCollection<ErrorMessage> _errorMessages = new ObservableCollection<ErrorMessage>(); //List that holds the error message for debug
private ObservableCollection<OrderDto> _queueDisplayItems = new ObservableCollection<OrderDto>();//List of order and quanities left. (DisplayQueue).
private ObservableCollection<DebugInfo> _queueDebugInfo = new ObservableCollection<DebugInfo>(); //
RetryToSubsribe method.
public void RetryToSubscribe()
{
try
{
WSDualHttpBinding binding = new WSDualHttpBinding();
binding.Name = "WsDualTcpEndpoint";
binding.CloseTimeout = new TimeSpan(0, 1, 0);
binding.OpenTimeout = new TimeSpan(0, 1, 0);
//binding.ReceiveTimeout = new TimeSpan(0, 0, 30);
binding.SendTimeout = new TimeSpan(0, 1, 0);
binding.BypassProxyOnLocal = false;
binding.TransactionFlow = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 65536;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.UseDefaultWebProxy = false;
binding.Security.Mode = WSDualHttpSecurityMode.None;
StringBuilder sb = new StringBuilder();
sb.Append("http://").Append(GetLocalIp()).Append(":808/WSDualOnXP");
_logger.Debug("Client base address : {1}.", sb.ToString());
binding.ClientBaseAddress = new Uri(sb.ToString());
EndpointAddress endpoint = new EndpointAddress(Settings.Default.ServerAddress);
service = new ProductionServiceClient(instanceContext, binding, endpoint);
ClientTokenRequest request = new ClientTokenRequest();
request.RequestId = NewRequestId;
request.StationNumbers = ScannerNumbers;
clientRequest = request;
service.Subscribe(request);
//Close the retry window.
this.Dispatcher.Invoke((Action)(() =>
{
//Set the background to default.
this.MainWindow.SetResourceReference(Window.BackgroundProperty, "MainBackground");
_retryScreen.Hide();
}));
}
catch (Exception ex)
{
_logger.Error(ex.Message);
}
}
if you can run windbg and follow along you might find out what exactly is leaking.
on your winxp machine open windbg and attach to the client process(let it run for a while to magnify the problem, i.e. the memory leak)
at the prompt type
you’ll get a list of all the objects in memory grouped by class. look for the ones that have the most number of instances. Hopefully that will give you an indication of what is the offending code.
other options are:
this will show you only instances of classes that start with MyClass.
Do not close windbg before detaching from the process otherwise it will kill your process.