1

Update I traced down a memory leak issue to the following: there was a memory leak when the program was running as a Windows Service, but not when running as a Console app.

Using ANTS Memory Profiler I saw that the leaked memory was held by the finalizer queue's GC root. So the question become: why were objects stuck in the finalizer queue when the program was run as a Windows Service?

Original question

I am developing a Windows Service in C#. It collects data from network devices periodically. Target framework is 4.6.

I use a TPL ActionBlock to be able to send the request parallely.

My issue: If I run the App as a regular console application, memory usage remains normal. (100 MB) In the debugger it is visible that Garbage Collection hits in regularly.

When the Application run in the session 0, as a Windows Service, the memory usage increases to out of memory exception. (6GB) Attaching Visual Studio Debugger to the Windows Service - it show that GC happens sometimes, but not as often as in regular Console.

Interestingly: this happens on Win10. On one Win7 Virtual machine- this memory problem is present in the service, and runned as a console app too.

Thank you very much for your help!

rendes
  • 117
  • 8
  • 3
    When it's using lots of memory, create a dump file and then use e.g. WinDBG/SOS to see *what you have lots of* and *what's keeping them rooted*. – Damien_The_Unbeliever Sep 14 '18 at 13:11
  • If your app only needs to run periodically, why not simply schedule it using Windows Task Scheduler? – Filburt Sep 14 '18 at 13:12
  • Note that one important difference between these might be the privileges of the user context. When it's a service, it is running under the LocalSystem account? If so, does this have access to the "network devices" (I wouldn't expect any network access for LocalSystem normally) – Ian Sep 14 '18 at 13:12
  • OOM is generally doesn't happen in a 64 bit system, it starts paging in and out of the disk due to huge default VM and since you can see 6GB, so it's surely 64 bit, are you sure its OOM – Mrinal Kamboj Sep 14 '18 at 13:15
  • It runs as LocalSystem, and I have no problem with network access. The app has been running as service for months now. As the number of network devices to observe increased, this problem occured. – rendes Sep 14 '18 at 13:18
  • It's OOM, I can see the exception in the Event Log, and also in the attached debugger. The development system is 64-bit. But the application is a 32-bit app. – rendes Sep 14 '18 at 13:20
  • There are only two ways to solve your problem - lucky guessing or analyzing your app behavior with the help of some sort of analysis. Viewing memory dump in WinDbg/SOS is one of the most typical ones. You may also use any sort of commercial profiler or PerfView's heap snapshots. – Konrad Kokosa Sep 14 '18 at 13:24
  • The ActionBlock doesn't cause OOMs and neither does TPL. It's always due to bugs. Lists for example use an internal buffer they replace with one twice as large when it runs out. If you try to add 1024 (2^10) items to a list, you may end up with 10 reallocations. The GC will collect them eventually but so many orphaned buffers can easily fragment memory that there's no memory block large enough for the new buffer – Panagiotis Kanavos Sep 14 '18 at 13:42
  • String operations also create new temporary strings, as strings are immutable. Those will remain in memory until they are GCd. Again, fragmentation. – Panagiotis Kanavos Sep 14 '18 at 13:43
  • Is your code so slow that the *ActionBlock* buffer keeps growing? Unless you set a `BoundedCapacity` the input buffer will accept whatever you send it until it's processed. If you consistently post more messages than the code can handle, the buffer will keep growing. – Panagiotis Kanavos Sep 14 '18 at 13:44
  • 2
    In short, post your code. The only way that running as a service affects memory usage is that the services stays alive far longer than a console application. If your code leaks you won't notice when you run the console app just once – Panagiotis Kanavos Sep 14 '18 at 13:46
  • This is my main concern: the console app vs windows service's behavior is not consistent. I sped up the application's behavior for testing. I run the Console app, and the service for the same time period. The service fills up the memory, the console app does not. I will make a short test project, and post it, if the problem persist with that. – rendes Sep 14 '18 at 15:28
  • I found the culprit: I did not dispose a Ping object. So the big question now is: why this is not a problem when runned as a Console Application? See the update at the end for code. – rendes Sep 15 '18 at 21:37

1 Answers1

4

Using ANTS Memory Profiler I found that the leaked memory was held by the finalizer queue's GC root.

This question lead me to the solution: How can I find the reason for a hung finalizer queue?

I converted my WinForms Application to a Console Applcation, then to a Windows service. I left the [STAThread] remark before the Main method. This caused the finalizer queue to hang, when the program was run as a Windows Service.

rendes
  • 117
  • 8