C # WCF Client Memory Leak on XP

I have a problem. I encoded a wcf client (WPF and C #) that uses wsHttpBinding. And I use duplex. I have a function that I call a wcf service every minute called KeepConnection. And I never close the client proxy because I need to constantly β€œconnect” to the client for service callbacks. But when running this client on Windows XP, I have a strange memory problem with my application. During normal operation on win 7 / vista, the application uses only 40 MB of memory in taskmanger. Xp is constantly increasing memory usage every second. I received more than 700 mb in 2 days.

Is there a way to fix this or is it related to XP. Thanks for the 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); } } 
+4
source share
2 answers

if you can run windbg and follow, you can find out what exactly is happening.

  • on your winxp machine, open windbg and join the client process (let it work for a while to increase the problem, i.e. memory leak)

  • at the type prompt

 If using .NET 2/3.5 .loadby sos mscorwks If using .NET 4 .loadby sos clr 
  • then run

! dumpheap -stat

You will get a list of all the objects in memory, grouped by class. Find the ones that have the most copies. Hopefully this will give you an indication of what the code violation is.

other parameters:

! dumpheap -stat -type MyClass *

this will only show you instances of classes that start with MyClass.

Do not close windbg before disconnecting from the process, otherwise it will kill your process.

+3
source

I assume that a memory leak occurs in a skipped timer handler. Can you post the code for RetryToSubscribe ().

0
source

All Articles