В чем основная причина того, что служба Windows .NET 3.5 имеет постоянно увеличивающееся число (#) дескрипторов GC? - PullRequest
1 голос
/ 25 февраля 2009

У меня есть служба Windows C #, работающая на .NET Framework 3.5, в которой постоянно растет число дескрипторов GC (с помощью системного монитора в Windows Server 2003).

Я обеспечил правильное удаление всех ресурсов, и в моем коде нет финализаторов.

'Размер кучи больших объектов' и '# байтов во всех кучах' являются сравнительно статичными, и я вижу, что "% времени в GC" показывает, что происходит сборка мусора.

Счетчик «Private Bytes» также увеличивается.

Этот симптом приводит к тому, что «Использование памяти» в Диспетчере задач растет примерно на 35 МБ в день, что недопустимо, поскольку Сервис в основном выполняет простой запрос SELECT для Oracle 10g и использует .NET TraceSources каждые 5 секунд. Вероятно, стоит упомянуть, что TraceSource выводит в журнал событий Windows И текстовый файл с использованием объектов .NET Listeners.

Кто-нибудь знает, почему «# GC Handles» постоянно увеличивается, так как я считаю, что это связано с моим увеличением «Использование памяти»?

Ответы [ 6 ]

2 голосов
/ 27 февраля 2009

ОК - отсортировано.

После изучения исходного кода для класса .NET TraceSource выясняется, что по замыслу ему принадлежат 2 списка WeakReferences - 1 для объектов TraceSource и один для Switch.

Это делается для поддержки метода RefreshAll.

Мне пришлось использовать Reflection, чтобы вручную очистить эти списки. Поэтому я больше не могу безопасно использовать метод RefreshAll, но по крайней мере у меня больше нет роста в Private Bytes и GC Handles.

Чтобы воспроизвести проблему, просто создайте целую загрузку объектов TraceSource и закройте их - вы можете увидеть «утечку».

1 голос
/ 20 марта 2009

Для чего бы то ни было, мы исправили эту проблему в .NET 4.0 для TraceSource и Switch.

Мы по-прежнему считаем целесообразным не создавать несколько различных экземпляров TraceSource (вместо этого создавать один статический экземпляр для каждого источника и делиться ими между потоками), но в некоторых случаях это невозможно, если вы используете третий партийная библиотека, которую вы не можете починить.

1 голос
/ 25 февраля 2009

Вы не освобождаете неуправляемые ресурсы, на которые ссылается ваш код должным образом.

Вы знакомы с фиксированным утверждением? Он может закрепить память так, чтобы к ней можно было обращаться небезопасным способом. Однако есть и другой способ сделать то, что, как мы могли бы утверждать, является небезопасным.

var handle = System.Runtime.InteropServices.GCHandle.Alloc(myObject,
        System.Runtime.InteropServices.GCHandleType.Pinned);

Приведенный выше тип кода - именно то, что может вызвать проблемы вашего типа. Если вы не укажете явно «.Free ()» в этой закрепленной памяти, вы не закончите сбор мусора для этого объекта, и у вас будет утечка памяти.

Я предполагаю, что подобное происходит с вашим провайдером Oracle 10g, если только вы не знаете, что делаете что-то еще, что может привести к утечке памяти.

0 голосов
/ 20 ноября 2014

Эта ссылка на опыт отладки должна добавить к этому обсуждению. Он дополняет обходной путь, опубликованный @ thehowler.

http://www.wintellect.com/blogs/jrobbins/is-that-a-weakreference-in-your-gen-2-or-are-you-just-glad-to-see-me

По сути, каждое новое распределение TraceSource добавляет в список WeakReference, который не является сборщиком мусора.

0 голосов
/ 06 апреля 2010
private void TidyWeakReferences(System.Diagnostics.TraceSource source) {

        try {
            // Clear down the Switch's WeakReferences
            TidyList(source, typeof(System.Diagnostics.Switch).GetFields(BindingFlags.NonPublic | BindingFlags.Static));
            // Clear down the Source's WeakReferences
            TidyList(source, typeof(System.Diagnostics.TraceSource).GetFields(BindingFlags.NonPublic | BindingFlags.Static));
        }
        catch { /* Nothing we can do here */ }
    }

private void TidyList(System.Diagnostics.TraceSource source, FieldInfo[] info) {

        List<WeakReference> list = null;

        foreach (FieldInfo fi in info) {

            if (fi.Name == "switches" | fi.Name == "tracesources") {

                list = (List<WeakReference>)fi.GetValue(null);
                lock (list) {
                    for (int i = list.Count - 1; i >= 0; i--) {
                        // Check to see if the GC has already collected these objects
                        if (!list[i].IsAlive) {
                            // It's dead, so remove it from the List (as .NET Framework 4.0 SHOULD fix.)
                            list.RemoveAt(i);
                        }
                    }
                }
            }
        }
0 голосов
/ 25 февраля 2009

Вы используете ODP.Net? Помните, что ODP.Net не полностью управляется и имеет собственный компонент. Используете ли вы какие-либо другие собственные ресурсы, например ActiveDirectory и т. Д. Помните, что даже если у вас есть .Net сборки, это тонкий слой над COM для таких вещей, как AD. Я видел большие утечки памяти в коде AD, который я использовал. У меня не было проблем с памятью в ODP.Net, и корпоративная служба моей компании работает с ODP.Net.

...