Какие объекты Excel Interop нужно очистить самостоятельно, а какие - с помощью GC.Collect () - PullRequest
3 голосов
/ 01 декабря 2009

Вопрос:

Я хочу задать вопрос в ответ на Ответ Майка Розенблюма на на этот вопрос . Речь шла об очистке объектов взаимодействия Excel. Было предложено несколько решений (например, обертки, не использующие более одной точки, убивающие процесс Excel), но мне больше всего понравилось решение Майка Розенблюма этой проблемы ( длинная статья о теме ).

В сущности, это говорит о том, что вы не слишком беспокоитесь обо всех ссылках, которые вы видите. Вы просто оставляете некоторые основные (например, ApplicationClass, Workbook и Worksheet). Сначала вы вызываете сборщик мусора, чтобы очистить все объекты, которые плавают вокруг, а затем явно очистите все основные ссылки, которые у вас есть, вызвав Marshal.FinalReleaseComObject (в обратном порядке важности).

Теперь у меня есть два вопроса по этому поводу.
Первый: как определить, на какие объекты мне нужно ссылаться? В примере Майка Розенблюма он сохраняет только Ranges, Worksheets, Workbooks и ApplicationClasses.
Второе: если есть еще объекты, как определить порядок их очистки (т. Е. «Порядок важности»)?

Заранее спасибо.


Обновление 1:

MattC предполагает, что для заказа важно только то, что приложение выпущено последним. Хотя в моей ссылке есть следующее предложение: «Вы также должны выпустить свои именованные ссылки в обратном порядке важности: сначала выберите объекты диапазона, затем рабочие листы, рабочие книги и, наконец, ваш объект приложения Excel». подразумевает, что есть больше порядка.

nobugz Предполагает, что достаточно установить все на null, а затем выполнить сборку мусора, но это, кажется, противоречит следующей цитате из статьи Майка Розенблюма : «Тогда вы бы подумали, что вы можно установить все ваши переменные = Nothing, а затем вызвать GC.Collect() в конце, и иногда это работает. Однако приложения Microsoft Office чувствительны к порядку, в котором объекты освобождаются, и, к сожалению, устанавливают ваши переменные = Nothing, а затем вызов GC.Collect() не гарантирует порядок высвобождения объектов. "

Обновление 2:

Дополнительная информация: В моем собственном приложении я много чего делаю с помощью графика. Я устанавливаю много свойств и т. Д. Как я понимаю, во многих местах я создаю новые COM-объекты. Я пытался убедиться, что никогда не использую двойные точки, и я пытался вызвать Marshal.FinalReleaseComObject для всех объектов, с которыми я закончил. Я не использовал подход обертки, потому что он привнес бы много вложенности.
EXCEL.exe не закрывалось после завершения работы моего приложения. Но ... он закрылся, когда я сказал своему приложению сделать ту же работу снова. Конечно, открылся новый EXCEL.exe, который не закрылся. Теперь я удалил все вызовы Marshal.FinalReleaseComObject и приложение работает точно так же. EXCEL.exe остается, пока я не скажу моему приложению повторить работу, но затем запускается и остается новый EXCEL.exe.

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

Не уверен, какие выводы я могу сделать из этого ...

Ответы [ 3 ]

3 голосов
/ 01 декабря 2009

У вас не должно возникнуть проблем с поиском возможных живых ссылок в вашем коде, они будут полями в вашем классе (ах). Или локальные переменные в методе очистки, это маловероятно. Список, приведенный в ссылке, - это просто объекты, которые вы, скорее всего, будете хранить в поле. Могут быть и другие, они будут поддерживать Excel так же живо, как объект Application.

Не думаю, что я бы порекомендовал подход отбойного молотка, который предлагается в ссылке, он просто скрывает потенциальную жизненную ссылку на RCW, который обертывает мертвый интерфейс COM. В лучшем случае вы будете иметь постоянную утечку к объекту RCW, в худшем случае это приведет к аварийному завершению вашей программы за исключением случаев, когда она случайно ссылается на объект. Bugz, конечно, просто не те, которые вы легко найдете. Все, что вам нужно сделать, это установить ваши ссылки на ноль, порядок не имеет значения, а затем собрать.

2 голосов
/ 01 декабря 2009

У меня была похожая проблема, это то, что мой улов и, наконец, выглядит для очистки. Надеюсь, это поможет.

        .......

        oWB._SaveAs(strCurrentDir +
           strFile, XlFileFormat.xlWorkbookNormal, null, null, false, false,       XlSaveAsAccessMode.xlShared, false, false, null, null);
            sumsheet.Activate();
            oWB.Close(null, null, null);
            oXL.Workbooks.Close();
            oXL.Quit();
        }
        catch (Exception theException)
        {
            theException.ToString();
        }
        #region COM Object Cleanup
        finally
        {
            // Cleanup
            GC.Collect();
            GC.WaitForPendingFinalizers();

            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oRng);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sumSheet);
            //System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oSheet);
            //oWB.Close(null, null, null);
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oWB);
            oXL.Quit();
            System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oXL);
        }
        #endregion

EDIT

Если вы заметили, я закомментировал sumSheet + oSheet (которые являются моими рабочими листами), потому что он не нужен. Этот код имеет твердое значение для меня без проблем. Я нашел, изменив порядок, я получил ошибки.

0 голосов
/ 01 декабря 2009

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

Затем выполните сбор GC.Collect, чтобы окончательно завершить процесс excel.exe.

...