Походит на причины лени len
для создания преобразователя:
len [1..100000] 0
-> len [2..100000] (0+1)
-> len [3..100000] (0+1+1)
и так далее. Необходимо вынудить len
уменьшить l
каждый раз:
len (x:xs) l = l `seq` len xs (l+1)
Для получения дополнительной информации, посмотрите http://haskell.org/haskellwiki/Stack_overflow .
Invoke действует как BeginInvoke / EndInvoke в том смысле, что она отправляет сообщение в поток пользовательского интерфейса, создает дескриптор и ожидает на этом дескрипторе, чтобы определить, когда метод Invoked завершен. Именно эта ручка «протекает». Вы можете видеть, что это безымянные события, используя Process Explorer для отслеживания дескрипторов во время работы приложения.
Если IASyncResult был IDisposable, удаление объекта позаботится об очистке дескриптора. На самом деле дескрипторы очищаются, когда сборщик мусора запускается и вызывает финализатор объекта IASyncResult. Вы можете увидеть это, добавив GC. Collect () после каждых 20 вызовов DoStuff - счетчик дескрипторов падает каждые 20 секунд. Конечно, «решение» проблемы путем добавления вызовов к GC.Collect () - это неправильный способ решения проблемы; пусть сборщик мусора выполняет свою работу.
Если вам не нужен вызов Invoke для синхронизации, используйте BeginInvoke вместо Invoke и не вызывайте EndInvoke; конечный результат будет делать то же самое, но никакие дескрипторы не будут созданы или «просочились».
Есть ли причина, по которой вы не можете использовать здесь System.Windows.Forms.Timer? Если таймер привязан к этой форме, вам даже не нужно будет ее вызывать.
Интересно - это не ответ, но, основываясь на комментариях Андрея, я бы подумал, что это не приведет к утечкам дескрипторов таким же образом, но это будет происходить с той же скоростью, что и упомянутый OP.
System.Threading.Timer timer;
public Form2()
{
InitializeComponent();
}
private void UpdateFormTextCallback()
{
this.Text = "Hello World!";
}
private Action UpdateFormText;
private void DoStuff(object value)
{
this.Invoke(UpdateFormText);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
timer = new System.Threading.Timer(new TimerCallback(DoStuff), null, 0, 500);
UpdateFormText = new Action(UpdateFormTextCallback);
}
Хорошо, я дал ему немного больше времени, и похоже, что на самом деле нет протекающих дескрипторов, это просто неопределенный характер сборщика мусора. Я увеличил его до 10 мс за тик, и он очень быстро поднимался вверх, а через 30 секунд снова падал.
Чтобы подтвердить теорию, я вручную вызвал GC.Collect () для каждого обратного вызова (не делайте этого в реальных проектах это было просто для проверки, там есть множество статей о том, почему это плохая идея) и счетчик дескрипторов был стабильным.