Не вызов Делегата. EndInvoke может вызвать утечку памяти … миф?

Я думаю, что необходимо начать их в C. Чем раньше они могут приобрести навык указателей, тем лучше.

Видят Понимать, что Указатели и Должны я изучать C.

14
задан Jeff Cyr 23 November 2009 в 15:26
поделиться

4 ответа

Я немного побегал test для вызова делегата Action и выдачи в нем исключения. Затем я убеждаюсь, что не затопляю пул потоков, поддерживая только указанное количество потоков, выполняющихся одновременно, и постоянно заполняю пул потоков после завершения вызова удаления. Вот код:

static void Main(string[] args)
{

    const int width = 2;
    int currentWidth = 0;
    int totalCalls = 0;
    Action acc = () =>
    {
        try
        {
            Interlocked.Increment(ref totalCalls);
            Interlocked.Increment(ref currentWidth);
            throw new InvalidCastException("test Exception");
        }
        finally
        {
            Interlocked.Decrement(ref currentWidth);
        }
    };

    while (true)
    {
        if (currentWidth < width)
        {
            for(int i=0;i<width;i++)
                acc.BeginInvoke(null, null);
        }

        if (totalCalls % 1000 == 0)
            Console.WriteLine("called {0:N}", totalCalls);

    }
}

После запуска в течение примерно 20 минут и более 30 миллионов вызовов BeginInvoke позже потребление частной байтовой памяти стало постоянным (23 МБ), как и количество дескрипторов. Похоже, утечки нет. Я прочитал книгу Джеффри Рихтерса C # через CLR, где он заявляет об утечке памяти. По крайней мере, это кажется неверным с .NET 3.5 SP1.

Тестовая среда: Windows 7 x86 .NET 3.5 с пакетом обновления 1 Intel 6600 Dual Core 2,4 ГГц

С уважением, Алоис Краус

6
ответ дан 1 December 2019 в 13:09
поделиться

В некоторых ситуациях BeginInvoke не требует EndInvoke (особенно при обмене сообщениями окна WinForms). Но определенно существуют ситуации, когда это имеет значение - например, BeginRead и EndRead для асинхронной связи. Если вы захотите запустить BeginWrite и забыть его, через некоторое время вы, вероятно, столкнетесь с серьезными проблемами с памятью.

Итак, ваш единственный тест не может быть окончательным. Чтобы правильно ответить на ваш вопрос, вам необходимо иметь дело с разными типами делегатов асинхронных событий.

2
ответ дан 1 December 2019 в 13:09
поделиться

Рассмотрим следующий пример, который работал на моей машине в течение нескольких минут и достиг рабочего набора 3,5 ГБ, прежде чем я решил его убить.

Action a = delegate { throw new InvalidOperationException(); };
while (true)
    a.BeginInvoke(null, null);

ПРИМЕЧАНИЕ: Обязательно запускайте его без подключен отладчик или отключены «прерывание при возникновении исключения» и «прерывание при необработанном пользователем исключении».

РЕДАКТИРОВАТЬ: Как указывает Джефф, проблема с памятью здесь не утечка, а просто случай перегрузки системы из-за постановки работы в очередь быстрее, чем она может быть обработана. В самом деле, то же самое поведение можно наблюдать, заменив бросок на любую подходящую длительную операцию. И использование памяти будет ограничено, если мы оставим достаточно времени между вызовами BeginInvoke.

Технически, это оставляет исходный вопрос без ответа. Однако, независимо от того, может ли это вызвать утечку, вызов Delegate.

1
ответ дан 1 December 2019 в 13:09
поделиться

От того, утечка памяти в настоящее время не зависит. Команда разработчиков фреймворка может в будущем изменить что-то таким образом, что может привести к утечке памяти, а поскольку официальная политика гласит: "Вы должны позвонить в EndInvoke", то это "по замыслу".

Неужели вы хотите рискнуть, что ваше приложение вдруг начнет утечку памяти когда-нибудь в будущем, потому что вы решили полагаться на наблюдаемое поведение, а не на документированные требования?

.
11
ответ дан 1 December 2019 в 13:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: