0

I'm running a windows service using TopShelf (based on console app in C# .NET 4.6.1) and I'm using Automapper 9.0.0. Every 10 seconds I run a task that processes about 1000 rows in a Ms SQL database (using entity framework), It seems like Automapper is taking up a lot of memory, and the memory grows each time the task is run (In task manager I can see the service taking up over 3000 Meg of RAM++).

I am new to Automapper and don't now if there is anything I need to code to release manually the memory. Somewhere I saw a huge amount of handlers and I was wondering if Automapper generates these handlers and how I can clean them up.

I tried putting a GC.Collect() at the end of each task but I don't seem to see a difference

enter image description here

Here is a code extract of my task:

private void _LiveDataTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            // setting up Ninject data injection
            var kernel = new StandardKernel();
            kernel.Load(Assembly.GetExecutingAssembly());
            //var stationExtesions = kernel.Get<IStationExtensionRepository>();
            //var ops = kernel.Get<IOPRepository>();
            //var opExtensions = kernel.Get<IOPExtensionRepository>();
            //var periods = kernel.Get<IPeriodRepository>();
            //var periodExtensions = kernel.Get<IPeriodExtensionRepository>();


            // create the LiveDataTasks object
            //var liveDataTasks = new LiveDataTasks(stationExtesions, ops, opExtensions, periods, periodExtensions);

            // sync the station live data
            //liveDataTasks.SyncLiveStationData();

            // force garbage collection to prevent memory leaks
            //GC.Collect();

            Console.WriteLine("LiveDataTimer: Total available memory before collection: {0:N0}", System.GC.GetTotalMemory(false));
            System.GC.Collect();
            Console.WriteLine("LiveDataTimer: Total available memory collection: {0:N0}", System.GC.GetTotalMemory(true));
        }

MOFICATIONS: I added some console outputs at the end of the code displaying the TotalMemory used. I removed GC.Collect() because it doesn't change anything and commented out most of the code accessing database. Now I realize that kernel.Load(Assembly.GetExecutingAssembly()); already makes memory grow very fast. See the following console capture: enter image description here Now if I comment out kernel.Load(Assembly.GetExecutingAssembly()); I get a stable memory situation again. How can I Dispose or unload the Kernel??? enter image description here

Ephie
  • 229
  • 2
  • 13
  • 1
    Are you disposing of any unmanaged objects in your code? This is the most common cause of memory leaks. Use the `using` statement for `IDisposable` objects. – jegtugado Nov 14 '19 at 10:45
  • Thanks jegtugado for your answer. How do I know wich objects are unmanaged object and wich ones are not? – Ephie Nov 14 '19 at 11:19
  • See question: [What exactly are unmanaged resources?](https://stackoverflow.com/questions/3433197/what-exactly-are-unmanaged-resources) – jegtugado Nov 14 '19 at 11:28

2 Answers2

1

Well, first of all you should not be doing Database work in a Service. Moving any big operation on DB data out of the DB will only add having to move the data over the Network twice - once to the client programm, once back to the DB - while also risking Race Conditions and a lot of other issues. My standing advice is: Keep DB work in the DB at all times.

As for the memory Footprint, this migth just be a missreading of the used Memory:

.NET uses the Garbage Collection Memory Management approach. One effect of it is that while the GC for any given Application does his collecting, all other threads have to be paused. As a result the GC is pretty lazy at running. If it only runs once on Application closure - that is the ideal case. So it tries avoding to run before that unessesarily. It will still run as much as it can, before it ever throws a OutOfMemoryException at you. But beyond that, it is perfectly happy to just keep allocating more and more object without cleaning up.

You can test if it is that by calling GC.Collect(). However such a call should generally never be in productive code. A alternate GC strategy (particular the one used for WebServers) might be better.

Christopher
  • 9,634
  • 2
  • 17
  • 31
0

I finally figured out what was happening: the kernel.Load(...) used to set up NInject data injection was increasing my memory:

var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());

So I moved this code from the function executed every x seconds to the constructor of the parent class where it is only executed once on initialisation.

This solved the problem.

Thanks guys for your inspiring help and comments!!!!

Ephie
  • 229
  • 2
  • 13