简体   繁体   中英

How can users enable Background Server GC in a desktop app without changing app.config?

I look after a WPF desktop app which many users run on varying hardware. Multiple threads constantly churn through a large volume of data.

Turning on .NET Framework 4.5 Background server garbage collection has shown significant performance improvements, however this comes at the cost of more memory being used and different CPU usage patterns. This is a potential problem for users with less-powerful machines, so I want to give the users who'd benefit most an opt-in to having server GC enabled instead of forcing it upon everyone.

The only way I've found so far to enable this is in App.Config :

<configuration>
  <runtime>
    <gcServer enabled="true"/>
  </runtime>
</configuration>

However, most users do not have permissions to edit this as the app resides within Program Files and they're not local admins. My ideal scenario would be a friendly-worded option which could restart the app with server GC enabled and remember their choice.

So my question is: Does anyone know of any other way to apply this setting?

I know it's probably wishful thinking - but ideally something dynamic at runtime, or maybe a command-line argument or environment variable which could be set in the context of the process. There are hints of this existing in CoreCLR with the complus_gcServer env variable .

I've read about global system settings which can enable this on the machine but I don't want to risk impacting any other apps and causing other adverse affects, I only want this to apply to my app.

As a last resort I could deploy two copies of the EXE with different config files and a launcher to choose the correct version to run, this seems extreme though.

Thanks for reading, any ideas welcome!

Here is an alternate suggestion. Leave server GC enabled as you have done. Then based on a user defined setting force GC to run if app memory goes above a certain threshold that you determine as the critical level.

Mind you if you follow this path you are effectively stating that you have better knowledge of when garbage collection should run that the CLR does. Most often than not I've found that the CLR does a better job on its own than when we interfere with it.

Code to check memory usage and run GC across either all generations or a specified generation

if (Math.Abs(DateTime.Now.Subtract(MemUsageLastCheckTime).TotalMinutes) > 5d)
{
    long UsedMemory;
    //UsedMemory = GC.GetTotalMemory(false); // Not as reliable
    UsedMemory = System.Diagnostics.Process.GetCurrentProcess().PagedMemorySize64;
    if (UsedMemory > 1073741824) // One GB in bytes 1 X 1024 X 1024 X 1024
    {
        GC.Collect(); // Collect all generations
        //GC.Collect(2,GCCollectionMode.Forced);; Or collect a specific generation and force it to run now
    }
    MemUsageLastCheckTime = DateTime.Now;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM