Windows service memory leak using TopShelf and Automapper c# - c#

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
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:
Now if I comment out kernel.Load(Assembly.GetExecutingAssembly()); I get a stable memory situation again. How can I Dispose or unload the Kernel???

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.

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!!!!

Related

Entity Framework performance over application lifetime

I am using EF 6.0 as an interface for my SQL Server database, and have been running into a re-occurring issue that I can't find a solution for other than setting up a auto-restart for the program.
I have a loop that will create a new DbContext and perform operations accordingly. After this loop goes for a few cycles the database operations will slow down to a crawl taking these iterations minutes to process when upon first launch it takes seconds.
I have tried things like disabling automatic change tracking and manual control of the garbage collection.
Here is what I am doing
while(true)
{
var ctx = new DBContext();
// ... Do operations
sleep(10000);
}
I've tried searching for an answer to this problem for awhile but have been unable to find one

Sharp SNMP Async method leaking stack memory

I'm trying the new 9.0.0 RC1 release of SharpSNMP for its async methods. It's easy to use - practically a drop-in replacement for the old synchronous method.
My code to poll a list of OIDs asynchronously is:
// create a new get request message
var message = new GetRequestMessage(Messenger.NextRequestId, VersionCode.V2, SNMPReadCommunity, oids);
// get a new socket
using (Socket udpSocket = SNMPManager.GetSocket())
{
// wait for the response (this is async)
var res = await message.GetResponseAsync(SNMPManager, new UserRegistry(), udpSocket);
// check the variables we received
CheckSnmpResults(res.Pdu().Variables);
}
I limit the number of OIDs per get-request to 25. My application connects to c.50 SNMP devices. Every 5 minutes a timer ticks and runs the above code several times in a loop in order to poll c.100 OIDs on each device. All good.
The problem is that the message.GetResponseAsync method is leaking memory. Every poll run adds 6 or 7 MB to my application's memory usage. Using the VS2015 memory profiler, I can see a large number of OverlappedData objects, each 65K, the number of which increases every time I run message.GetResponseAsync. So running this to receive c.200 SNMP get-requests every 5 minutes means my application's memory use quickly rockets.
Am I using message.GetResponseAsync incorrectly somehow? Is this a bug in SharpSNMPLib?
Thanks,
Giles
A temp answer right now.
The leak is caused by the fact that SocketAsyncEventArgs is not reused. This kind of object should be reused (as well as the Socket object) if a manager tries to manage an agent with multiple operations.
The current design does not allow such reuse. Thus, an overall redesign is needed.
I already have some ideas on how to move on, but probably it won't be able to make into 9.0 release. See if 9.5 can be the first release with the new design. And then I will go back and update this answer.
Updated: this commit contains a quick fix to dispose the args object. But it does not enable reuse yet.

Minimizing WCF service client memory usage

I'm implementing a WCF service client which is aimed to test several service methods. That's done by using standard generated proxy class created by Add Web Reference (inherited from System.Web.Services.Protocols.SoapHttpClientProtocol). What I need to do is execute certain type of requests many times simultaneously to see how it will affect server performance (something like capacity testing for server infrastructure).
Here's the problem - each of responses to these requests is pretty large (~10-100 mb) and I see that only few calls like
// parametersList.Count = 5
foreach(var param in parametersList)
{
var serviceResponse = serviceWebReferenceProxy.ExecuteMethod(param);
// serviceResponse is not saved anywhere else,
// expected to be GC'd after iteration
}
causes Private bytes of process to jump to ~500 mb of memory and Working Set to 200-300 mb. I suspect running them in parallel and increasing iterations count to 100-200 as needed will definitely cause StackOverflow/OutOfMemoryException. How this can be done then? I'm expecting removal of assigning service method response to variable will help, but that's a problem because I need to see each response's size. I'm looking for some sort of instant and guaranteed memory cleanup after each iteration.
Refactored logic to reuse existing objects as much as possible, which gave an ability to run more clients. After certain period of time garbage collecting becomes very slow but performance is acceptable.

Very High Memory Usage in .NET 4.0

I have a C# Windows Service that I recently moved from .NET 3.5 to .NET 4.0. No other code changes were made.
When running on 3.5, memory utilzation for a given work load was roughly 1.5 GB of memory and throughput was 20 X per second. (The X doesn't matter in the context of this question.)
The exact same service running on 4.0 uses between 3GB and 5GB+ of memory, and gets less than 4 X per second. In fact, the service will typically end up stalling out as memory usage continue to climb until my system is siting at 99% utilization and page file swapping goes nuts.
I'm not sure if this has to do with garbage collection, or what, but I'm having trouble figuring it out. My window service uses the "Server" GC via the config file switch seen below:
<runtime>
<gcServer enabled="true"/>
</runtime>
Changing this option to false didn't seem to make a difference. Futhermore, from the reading I've done on the new GC in 4.0, the big changes only effect the workstation GC mode, not server GC mode. So perhaps GC has nothing to do with the issue.
Ideas?
Well this was an interesting one.
The root cause turns out to be a change in the behavior of SQL Server Reporting Services' LocalReport class (v2010) when running this on top of .NET 4.0.
Basically, Microsoft altered the behavior of RDLC processing so that each time a report was processed it was done so in a seperate application domain. This was actually done specifically to address a memory leak caused by the inability to unload assemblies from app domains. When the LocalReport class processed an RDLC file, it actually creates an assembly on the fly and loads it into the app domain.
In my case, due to the large volume of report I was processing, this was resulting in very large numbers of System.Runtime.Remoting.ServerIdentity objects being created. This was my tip off to the cause, as I was confused as to why processing an RLDC required remoting.
Of course, to call a method on a class in another app domain, remoting is exactly what you use. In .NET 3.5, this wasn't necessary as, by default, the RDLC-assembly was loaded into the same app domain. In .NET 4.0, however, a new app domain is created by default.
The fix was fairly easy. First I needed to go enable legacy security policy using the following config:
<runtime>
<NetFx40_LegacySecurityPolicy enabled="true"/>
</runtime>
Next, I needed to force the RDLCs to be processed in the same app domain as my service by calling the following:
myLocalReport.ExecuteReportInCurrentAppDomain(AppDomain.CurrentDomain.Evidence);
This resolved the issue.
I ran into this exact issue. And it is true that app domains are created and not cleaned up. However I wouldn't recommend reverting to legacy. They can be cleaned up by ReleaseSandboxAppDomain().
LocalReport report = new LocalReport();
...
report.ReleaseSandboxAppDomain();
Some other things I also do to clean up:
Unsubscribe to any SubreportProcessing events,
Clear Data Sources,
Dispose the report.
Our windows service processes several reports a second and there are no leaks.
I'm pretty late to this, but I have a real solution and can explain why!
It turns out that LocalReport here is using .NET Remoting to dynamically create a sub appdomain and run the report in order to avoid a leak internally somewhere. We then notice that, eventually, the report will release all the memory after 10 to 20 minutes. For people with a lot of PDFs being generated, this isn't going to work. However, the key here is that they are using .NET Remoting. One of the key parts to Remoting is something called "Leasing". Leasing means that it will keep that Marshal Object around for a while since Remoting is usually expensive to setup and its probably going to be used more than once. LocalReport RDLC is abusing this.
By default, the leasing time is... 10 minutes! Also, if something makes various calls into it, it adds another 2 minutes to the wait time! Thus, it can randomly be between 10 and 20 minutes depending how the calls line up. Luckily, you can change how long this timeout happens. Unluckily, you can only set this once per app domain... Thus, if you need remoting other than PDF generation, you will probably need to make another service running it so you can change the defaults. To do this, all you need to do is run these 4 lines of code at startup:
LifetimeServices.LeaseTime = TimeSpan.FromSeconds(5);
LifetimeServices.LeaseManagerPollTime = TimeSpan.FromSeconds(5);
LifetimeServices.RenewOnCallTime = TimeSpan.FromSeconds(1);
LifetimeServices.SponsorshipTimeout = TimeSpan.FromSeconds(5);
You'll see the memory use start to rise and then within a few seconds you should see the memory start coming back down. Took me days with a memory profiler to really track this down and realize what was happening.
You can't wrap ReportViewer in a using statement (Dispose crashes), but you should be able to if you use LocalReport directly. After that disposes, you can call GC.Collect() if you want to be doubly sure you are doing everything you can to free up that memory.
Hope this helps!
Edit
Apparently, you should call GC.Collect(0) after generating a PDF report or else it appears the memory use could still get high for some reason.
You might want to
profile the heap
use WinDbg + SOS.dll to establish what resource is being leaked and from where the reference is held
Perhaps some API has changed semantics or there might even be a bug in the 4.0 version of the framework
Just for completeness, if anyone is looking for the equivalent ASP.Net web.config setting, it is:
<system.web>
<trust legacyCasModel="true" level="Full"/>
</system.web>
ExecuteReportInCurrentAppDomain works the same.
Thanks to this Social MSDN reference.
It seems as though Microsoft tried putting the report into its own separate memory space to work around all of the memory leaks rather than fix them. In doing so, they introduced some hard crashes, and ended up having more memory leaks anyway. They seem to cache the report definition, but never use it and never clean it up, and every new report creates a new report definition, taking up more and more memory.
I played around with doing the same thing: use a separate app domain and marshal the report over to it. I think that is a terrible solution and makes a mess very quickly.
What I did instead is similar: split the reporting part of your program out into its own separate reports program. This turns out to be a good way to organize your code anyway.
The tricky part is passing information to the separate program. Use the Process class to start a new instance of the reports program and pass any parameters it needs on the command line. The first parameter should be an enum or similar value indicating the report that should be printed. My code for this in the main program looks something like:
const string sReportsProgram = "SomethingReports.exe";
public static void RunReport1(DateTime pDate, int pSomeID, int pSomeOtherID) {
RunWithArgs(ReportType.Report1, pDate, pSomeID, pSomeOtherID);
}
public static void RunReport2(int pSomeID) {
RunWithArgs(ReportType.Report2, pSomeID);
}
// TODO: currently no support for quoted args
static void RunWithArgs(params object[] pArgs) {
// .Join here is my own extension method which calls string.Join
RunWithArgs(pArgs.Select(arg => arg.ToString()).Join(" "));
}
static void RunWithArgs(string pArgs) {
Console.WriteLine("Running Report Program: {0} {1}", sReportsProgram, pArgs);
var process = new Process();
process.StartInfo.FileName = sReportsProgram;
process.StartInfo.Arguments = pArgs;
process.Start();
}
And the reports program looks something like:
[STAThread]
static void Main(string[] pArgs) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var reportType = (ReportType)Enum.Parse(typeof(ReportType), pArgs[0]);
using (var reportForm = GetReportForm(reportType, pArgs))
Application.Run(reportForm);
}
static Form GetReportForm(ReportType pReportType, string[] pArgs) {
switch (pReportType) {
case ReportType.Report1: return GetReport1Form(pArgs);
case ReportType.Report2: return GetReport2Form(pArgs);
default: throw new ArgumentOutOfRangeException("pReportType", pReportType, null);
}
}
Your GetReportForm methods should pull the report definition, make use of relevant arguments to obtain the dataset, pass the data and any other arguments to the report, and then place the report in a report viewer on a form and return a reference to the form. Note that it is possible to extract much of this process so that you can basically say 'give me a form for this report from this assembly using this data and these arguments'.
Also note that both programs must be able to see your data types that are relevant to this project, so hopefully you have extracted your data classes into their own library, which both of these programs can share a reference to. It would not work to have all of the data classes in the main program, because you would have a circular dependency between the main program and the report program.
Don't over do it with the arguments, either. Do any database querying you need in the reports program; don't pass a huge list of objects (which probably wouldn't work anyway). You should just be passing simple things like database ID fields, date ranges, etc. If you have particularly complex parameters, you might need to push that part of the UI to the reports program too and not pass them as arguments on the command line.
You can also put a reference to the reports program in your main program, and the resulting .exe and any related .dlls will be copied to the same output folder. You can then run it without specifying a path and just use the executable filename by itself (ie: "SomethingReports.exe"). You can also remove the reporting dlls from the main program.
One issue with this is that you will get a manifest error if you've never actually published the reports program. Just dummy publish it once, to generate a manifest and then it will work.
Once you have this working, it's very nice to see your regular program's memory stay constant when printing a report. The reports program appears, taking up more memory than your main program, and then disappears, cleaning it up completely with your main program taking up no more memory than it already had.
Another issue might be that each report instance will now take up more memory than before, since they are now entire separate programs. If the user prints a lot of reports and never closes them, it will use up a lot of memory very fast. But I think this is still much better since that memory can easily be reclaimed simply by closing the reports.
This also makes your reports independent of your main program. They can stay open even after closing the main program, and you can generate them from the command line manually, or from other sources as well.

ASP.NET Persistent Caching ("Lazy loading"-style?)

I'm having some trouble getting my cache to work the way I want.
The problem:
The process of retrieving the requested data is very time consuming. If using standard ASP.NET caching some users will take the "hit" of retrieving the data. This is not acceptable.
The solution?:
It is not super important that the data is 100% current. I would like to serve old invalidated data while updating the cached data in another thread making the new data available for future requests. I reckon that the data needs to be persisted in some way in order to be able to serve the first user after application restart without that user taking the "hit".
I've made a solution which does somewhat of the above, but I'm wondering if there is a "best practice" way or of there is a caching framework out there already supporting this behaviour?
There are tools that do this, for example Microsofts ISA Server (may be a bit expensive / overkill).
You can cache it in memory using Enterprise Libary Caching. Let your users read from Cache, and have other pages that update the Cache, these other pages should be called as regularly as you need to keep the data upto date.
You could listen when the Cached Item is Removed and Process then,
public void RemovedCallback(String k, Object v, CacheItemRemovedReason r)
{
// Put Item Back IN Cache, ( so others can use it until u have finished grabbing the new data)
// Spawn Thread to Go Get Up To Date Data
// Over right Old data with new return...
}
in global asax
protected void Application_Start(object sender, EventArgs e)
{
// Spawn worker thread to pre-load critical data
}
Ohh...I have no idea if this is best practice, i just thought it would be slick~
Good Luck~
I created my own solution with a Dictionary/Hashtable in memory as a duplicate of the actual cache. When a method call came in requesting the object from cache and it wasn't there but was present in memory, the memory stored object was returned and fired a new thread to update the object in both memory and the cache using a delegate method.
You can do this pretty easily with the Cache and Timer classes built into .NET. The Timer runs on a separate thread.
And I actually wrote a very small wrapper library called WebCacheHelper which exposes this functionality in an overloaded constructor. The library also serves as a strongly typed wrapper around the Cache object.
Here's an example of how you could do this...
public readonly static WebCacheHelper.Cache<int> RegisteredUsersCount =
new WebCacheHelper.Cache<int>(new TimeSpan(0, 5, 0), () => GetRegisteredUsersCount());
This has a lazy loading aspect to it where GetRegisteredUsersCount() will be executed on the calling thread the instant that RegisteredUsersCount is first accessed. However, after that it's executed every 5 minutes on a background thread. This means that the only user who will be penalized with a slow wait time will be the very first user.
Then getting the value is as simple as referencing RegisteredUsersCount.Value.
Yeah you could just cache the most frequently accessed data when your app starts but that still means the first user to trigger that would "take the hit" as you say (assuming inproc cache of course).
What I do in this situation is using a CacheTable in db to cache the latest data, and running a background job (with a windows service. in a shared environment you can use threads also) that refreshes the data on the table.
There is a very little posibility to show user a blank screen. I eliminate this by also caching via asp.net cache for 1 minute.
Don't know if it's a bad design, but it's working great without a problem on a highly used web site.

Categories