AppDomain.Unload

Badabum
Дата: 30.04.2014 16:49:08
добрый день.
Есть сервис, при вызове создается домен, загружаются из BD необходимые сборки (это было нужно из-за поддержки версий, т.е. в одном случае одна версия в другом другая). Домен сохраняется в некий пул вида
Dictionary<String, AppDomain> listDomain
,
пул инициализируется вот таким образом:
public void Init(int processQueueInterval = INTERVAL_UNLOAD_DOMAIN)
        {
            //if (string.IsNullOrEmpty(pathToLogFile))
            if (listDomain != null)
                return;

            listDomain = new Dictionary<string, AppDomain>();
            queue = new Queue<String>();

            if (processQueueInterval > 0)
            {
                logQueueThread = new Thread(() =>
                {
                    while (workExists)
                    {
                        Thread.Sleep(processQueueInterval);
                             // Выгрузка домена
                            ProcessQueue();
                    }
                });
                logQueueThread.IsBackground = true;
                logQueueThread.Start();
            }
        }

При необходимости выгрузить домен, его имя бросается в очередь
 Queue<String> queue
, где он должен выгрузиться
private void ProcessQueue()
        {
            bool runGC = queue.Count > 0;
            while (queue.Count > 0)
            {
                String nameDomain = queue.Dequeue();
                if (nameDomain != null)
                {
                    RemoveDomain(nameDomain);
                }
            }

            if ((runGC) && (listDomain.Count == 0))
                GC.Collect(2);
        }

Проблема с раходом памяти, т.к. в итоге все падает когда выело всю память. Т.е. код для выгрузки вызывается, но толку от этого ни какого. То-ли GC не успевает отработать, то ли он вообще не выгрузился.....
Есть какая идея - куда копать?
Badabum
Дата: 30.04.2014 17:00:34
да, сам метод выгрузки:
private void RemoveDomain(String nameDomain)
        {
            if (!listDomain.ContainsKey(nameDomain)) return;
            AppDomain.Unload(listDomain[nameDomain]);
            Guid sId = Guid.Empty;
            Guid.TryParse(nameDomain, out sId);
            Log.WriteLog(sId, "DomainManager.RemoveDomain", "Unloaded domain: " + nameDomain, LogWarning.Trace);
            listDomain.Remove(nameDomain);
            workExists = (listDomain.Count != 0);
        }

Имя домена задается как Guid, посему и парсится им-же.
petalvik
Дата: 30.04.2014 17:14:51
Badabum,

копать в сторону профилировщика. Профайлер покажет, где именно растёт память.

Queue<string> - это наверняка System.Collections.Generic? Тогда ахтунг... Непотокобезопасная очередь используется в разных потоках.
Также нутром чую, что workExists не volatile.
Ну и вместо Thread.Sleep лучше применить какой-нибудь примитив синхронизации.
Badabum
Дата: 30.04.2014 17:29:28
Мдя.. ищу чем можно смотреть...
По поводу workExists - точно так, поправлю...
А вот чем Queue не подходит - доступ к нему залочен локом:
public void UnloadDomain(String nameDomain)
        {
            lock (lockObj)
            {
                if (queue == null) return;
                Guid sId = GetSid(nameDomain);
                Log.WriteLog(sId, "DomainManager.UnloadDomain", "Поставлен на удаление domain: " + nameDomain, LogWarning.Trace);
                queue.Enqueue(nameDomain);
            }
        }

А дальше вся работа в методе
ProcessQueue()
. Queue содержит имена доменов, которые нужно выгрузить. Какие могут быть грабли?