C# 为什么通过GCLatencyMode.LowLatency最小化垃圾收集会对执行时间产生负面影响?
我不明白为什么将C# 为什么通过GCLatencyMode.LowLatency最小化垃圾收集会对执行时间产生负面影响?,c#,multithreading,memory-management,garbage-collection,heap,C#,Multithreading,Memory Management,Garbage Collection,Heap,我不明白为什么将GCSettings.LatencyMode设置为GCLatencyMode.LowLatency会对执行时间产生负面影响 请考虑下面的代码。请注意,我在线程池中有足够的线程,因此我确保这里没有引入延迟。另外,我在这台机器上有足够的内存。在Interactive和LowLatency中运行的差异会导致LowLatency的执行时间增加3倍 class Program { static void Main(string[] args) { //cap
GCSettings.LatencyMode
设置为GCLatencyMode.LowLatency
会对执行时间产生负面影响
请考虑下面的代码。请注意,我在线程池中有足够的线程,因此我确保这里没有引入延迟。另外,我在这台机器上有足够的内存。在
Interactive
和LowLatency
中运行的差异会导致LowLatency
的执行时间增加3倍
class Program
{
static void Main(string[] args)
{
//capture current latency mode
var currentLatencyMode = GCSettings.LatencyMode;
//set low latency mode to minimize garbage collection
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
var watch = new Stopwatch();
var numberTasksToSpinOff = 4;
var numberItems = 20000;
var random = new Random((int)DateTime.Now.Ticks);
var dataPoints = Enumerable.Range(1, numberItems).Select(x => random.NextDouble()).ToList();
var workers = new List<Worker>();
//structure workers
for (int i = 1; i <= numberTasksToSpinOff; i++)
{
workers.Add(new Worker(i, dataPoints));
}
//start timer
watch.Restart();
//parallel work
if (workers.Any())
{
var processorCount = Environment.ProcessorCount;
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = processorCount };
Parallel.ForEach(workers, parallelOptions, DoSomeWork);
}
//stop timer
watch.Stop();
//reset latency mode
GCSettings.LatencyMode = currentLatencyMode;
Console.WriteLine($"Time it took to complete in Milliseconds: {watch.ElapsedMilliseconds}");
Console.WriteLine("Press key to quit");
Console.ReadLine();
}
private static void DoSomeWork(Worker worker)
{
Console.WriteLine($"WorkerId: {worker.WorkerId} -> New Tasks spun off with in Thread Id: {Thread.CurrentThread.ManagedThreadId}");
var indexPos = 0;
foreach (var dp in worker.DataPoints)
{
var subset = worker.DataPoints.Skip(indexPos).Take(worker.DataPoints.Count - indexPos).ToList();
indexPos++;
}
}
}
public class Worker
{
public int WorkerId { get; set; }
public List<double> DataPoints { get; set; }
public Worker(int workerId, List<double> dataPoints)
{
WorkerId = workerId;
DataPoints = dataPoints;
}
}
类程序
{
静态void Main(字符串[]参数)
{
//捕获当前延迟模式
var currentLatencyMode=GCSettings.LatencyMode;
//设置低延迟模式以最小化垃圾收集
GCSettings.LatencyMode=GCLatencyMode.LowLatency;
var watch=新秒表();
var numberTasksToSpinOff=4;
var numberItems=20000;
var random=new random((int)DateTime.Now.Ticks);
var dataPoints=Enumerable.Range(1,numberItems).Select(x=>random.NextDouble()).ToList();
var workers=新列表();
//结构工人
对于(int i=1;i这里没有免费的午餐,垃圾收集器必须做一项工作,并尝试考虑您的顾虑。但是,没有一种方法适合所有人(特别是在试图突破其限制时)
要回收对象,垃圾收集器必须停止所有正在执行的
应用程序中的线程。在某些情况下,例如
应用程序检索数据或显示内容,这是一个完整的垃圾
收集可能发生在关键时间,并影响性能。您
可以通过设置
GCSettings.LatencyMode属性设置为
System.Runtime.GCLatencyMode
值
更进一步
LowLatency抑制第2代收集并仅执行
第0代和第1代集合。它只能在短时间内使用
时间。在较长的时间内,如果系统处于内存压力下,
垃圾收集器将触发一个收集,该收集可以
暂停应用程序并中断时间关键型操作。此
此设置仅适用于工作站垃圾回收
在低延迟期间,第2代收集将被抑制,除非发生以下情况:
- 系统从操作系统接收内存不足通知
- 应用程序代码通过调用GC.Collect方法并为generation参数指定2来诱导收集
使用低延迟的指导原则
使用低级延迟模式时,请考虑以下准则:
保持低延迟的时间段尽可能短
避免在低延迟期间分配大量内存。由于垃圾收集,可能会发生内存不足通知
回收更少的对象
在低延迟模式下,尽量减少分配的数量,尤其是分配到大型对象堆和
固定对象
请注意可能正在分配的线程。由于LatencyMode属性设置是进程范围的,因此可以生成
可能正在分配的任何线程上的OutOfMemoryException
根据指南(并考虑到您之前的问题),您显然试图在其预期理想操作条件下使用它
我认为对你来说最重要的一点是1和3,显然垃圾收集器要么是被一个gc.collect
命令强制清理,要么是它觉得需要清理你正在分配的大量内存,即11 Gig
这里的关键是,如果不知道垃圾收集器的确切内部结构和工作原理,也不知道您正在做什么以及原因,那么除了“在您的情况下,它确实会影响执行时间”之外,您的问题可能永远不会有一个理想的答案这里没有免费的午餐,垃圾收集器必须做好工作,并尽力考虑您的顾虑。然而,这里没有一刀切的办法(特别是在试图突破其限制时)
要回收对象,垃圾收集器必须停止所有正在执行的
应用程序中的线程。在某些情况下,例如
应用程序检索数据或显示内容,这是一个完整的垃圾
收集可能发生在关键时间,并影响性能。您
可以通过设置
GCSettings.LatencyMode属性设置为
System.Runtime.GCLatencyMode
值
更进一步
LowLatency抑制第2代收集并仅执行
第0代和第1代集合。它只能在短时间内使用
时间。在较长的时间内,如果系统处于内存压力下,
垃圾收集器将触发一个收集,该收集可以
暂停应用程序并中断时间关键型操作。此
此设置仅适用于工作站垃圾回收
在低延迟期间,第2代收集将被抑制,除非发生以下情况:
- 系统从操作系统接收内存不足通知
- 应用程序代码通过调用GC.Collect方法并为generation参数指定2来诱导收集
使用低延迟的指导原则
使用低级延迟模式时,请考虑以下准则:
保持低延迟的时间段尽可能短
避免在低延迟期间分配大量内存。低内存