Можете ли вы заблокировать вызовы GC.Collect и GC.WaitForPendingFinalizers? - PullRequest
9 голосов
/ 08 декабря 2010

Учитывая следующее:

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration);

Принимая во внимание режимы многопоточности и сборки мусора, при каких обстоятельствах вы бы зашли в тупик на WaitForPendingFinalizers?

Примечание: я не ищу ответов о причинах, по которым вам не следует звонить GC.Collect.

Ответы [ 3 ]

5 голосов
/ 08 декабря 2010
// causes a deadlock when built with release config and no debugger attached
// building in debug mode and/or attaching the debugger might keep
// badIdea alive for longer, in which case you won't see the deadlock
// unless you explicitly set badIdea to null after calling Monitor.Enter

var badIdea = new BadIdea();
Monitor.Enter(badIdea);

GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration);

// ...

public class BadIdea
{
    ~BadIdea()
    {
        lock (this)
        {
            // ...
        }
    }
}
2 голосов
/ 08 декабря 2010

Вы не столкнетесь с какой-либо тупиковой ситуацией при вызове GC.Collect и GC.WaitForPendingFinalizers , если только вы не обращаетесь к управляемым объектам в ваших Finalize методах. Вызов методов других объектов с общедоступной областью действия может потенциально привести к непредсказуемым результатам, включая тупик. Причина в том, что вы не полностью контролируете шаблоны блокировки этих других объектов. Он может быть заблокирован любым пользователем, пока ваш метод финализатора пытается получить к нему доступ.

Кроме того, явная блокировка this в финализаторе почти гарантированно приведет к тупику, как показывает ответ LukeH. Вы можете прочитать оригинальную статью Джеффри Рихтера об этом здесь .

Как правило, вы должны высвобождать неуправляемые ресурсы только в ваших финализаторах, что должно устранить любые подобные опасения по поводу взаимоблокировок.

2 голосов
/ 08 декабря 2010

Существует известный тупик на WaitForPendingFinalizers, описанный Джеффри Рихтером. Это показано здесь: http://haacked.com/archive/2005/04/12/neverlockthis.aspx

class MyClass
{

private bool isDisposed = false;

    ~MyClass()
    {
        lock(this)
        {
            if(!isDisposed)
            {
                // ...
            }
        }
    }
}
...
MyClass instance = new MyClass();

Monitor.Enter(instance);
instance = null;

GC.Collect();
GC.WaitForPendingFinalizers();

Это вызвано неправильным использованием блокировки (это). В любом случае, это ситуация, когда WaitForPendingFinalizers заблокирован.

...