使用 new 关键字进行分配时,CLR 是否会在内存不足时通过 Sleep 语句进行限制?
When allocating with the new keyword, does the CLR ever throttle via a Sleep statement when memory is low?
我在 Stack Overflow 上看到 this answer:
当分配速度快于垃圾收集速度时,您将 运行 陷入 OOM。如果你进行大量分配,CLR 将插入一个 Sleep(xx) 来限制分配,但这在你的极端情况下是不够的。
所以,我没有读到任何有关 CLR 节流分配的信息,方法是在内存不足时插入 Sleep 语句来减慢分配速度。任何人都可以确认这是不是真的?如果是真的,那么有没有任何文件谈及细节?我已尝试进行 Google 搜索,但找不到任何支持此声明的内容。
非常感谢@AloisKraus research, patience, and links to the code in GC.cpp 在方法 gc_heap::allocate_small:
中显示了以下代码
#if defined (BACKGROUND_GC) && !defined (MULTIPLE_HEAPS)
if (recursive_gc_sync::background_running_p())
{
background_soh_alloc_count++;
if ((background_soh_alloc_count % bgc_alloc_spin_count) == 0)
{
add_saved_spinlock_info (false, me_release, mt_alloc_small);
leave_spin_lock (&more_space_lock_soh);
bool cooperative_mode = enable_preemptive();
GCToOSInterface::Sleep (bgc_alloc_spin);
disable_preemptive (cooperative_mode);
enter_spin_lock (&more_space_lock_soh);
add_saved_spinlock_info (false, me_acquire, mt_alloc_small);
}
else
{
//GCToOSInterface::YieldThread (0);
}
}
#endif //BACKGROUND_GC && !MULTIPLE_HEAPS
关键一行是:
GCToOSInterface::Sleep (bgc_alloc_spin);
bgc_alloc_spin 被初始化为 2,因此这会导致线程休眠 2 毫秒 (ms)。该代码每调用 140 次仅执行一次,并且仅在发生后台 GC 时执行。但是,这仍然足以导致 14,000 多个线程在 1 秒内休眠 2 毫秒,这将对性能产生重大影响(请参阅 Alois Kraus 的简单数学讨论)。
编辑 1
在回答@Enigmativity 时,GCToOSInterfaceSleep 方法定义为:
void GCToOSInterface::Sleep(uint32_t sleepMSec)
{
::Sleep(sleepMSec);
}
这位于 gcenv.windows.cpp。
总之,我提出的问题的答案是肯定的,当后台 GC 为 运行 时,CLR 会限制分配。限制分配的基本原理似乎是允许后台 GC 更快更有效地完成其工作。
我在 Stack Overflow 上看到 this answer:
当分配速度快于垃圾收集速度时,您将 运行 陷入 OOM。如果你进行大量分配,CLR 将插入一个 Sleep(xx) 来限制分配,但这在你的极端情况下是不够的。
所以,我没有读到任何有关 CLR 节流分配的信息,方法是在内存不足时插入 Sleep 语句来减慢分配速度。任何人都可以确认这是不是真的?如果是真的,那么有没有任何文件谈及细节?我已尝试进行 Google 搜索,但找不到任何支持此声明的内容。
非常感谢@AloisKraus research, patience, and links to the code in GC.cpp 在方法 gc_heap::allocate_small:
中显示了以下代码#if defined (BACKGROUND_GC) && !defined (MULTIPLE_HEAPS)
if (recursive_gc_sync::background_running_p())
{
background_soh_alloc_count++;
if ((background_soh_alloc_count % bgc_alloc_spin_count) == 0)
{
add_saved_spinlock_info (false, me_release, mt_alloc_small);
leave_spin_lock (&more_space_lock_soh);
bool cooperative_mode = enable_preemptive();
GCToOSInterface::Sleep (bgc_alloc_spin);
disable_preemptive (cooperative_mode);
enter_spin_lock (&more_space_lock_soh);
add_saved_spinlock_info (false, me_acquire, mt_alloc_small);
}
else
{
//GCToOSInterface::YieldThread (0);
}
}
#endif //BACKGROUND_GC && !MULTIPLE_HEAPS
关键一行是:
GCToOSInterface::Sleep (bgc_alloc_spin);
bgc_alloc_spin 被初始化为 2,因此这会导致线程休眠 2 毫秒 (ms)。该代码每调用 140 次仅执行一次,并且仅在发生后台 GC 时执行。但是,这仍然足以导致 14,000 多个线程在 1 秒内休眠 2 毫秒,这将对性能产生重大影响(请参阅 Alois Kraus 的简单数学讨论)。
编辑 1
在回答@Enigmativity 时,GCToOSInterfaceSleep 方法定义为:
void GCToOSInterface::Sleep(uint32_t sleepMSec)
{
::Sleep(sleepMSec);
}
这位于 gcenv.windows.cpp。
总之,我提出的问题的答案是肯定的,当后台 GC 为 运行 时,CLR 会限制分配。限制分配的基本原理似乎是允许后台 GC 更快更有效地完成其工作。