#delphi #delphi-2007 #refcounting
#delphi #delphi-2007 #пересчет
Вопрос:
в моей программе я могу загрузить каталог: iCatalog
Каталог здесь содержит много пересчитанных структур (Icollections IItems, IElements, iRules и т. Д.)
когда я хочу перейти в другой каталог, я загружаю новый каталог, но автоматическое освобождение предыдущего экземпляра iCatalog требует времени, замораживая мое приложение на 2 секунды или более.
мой вопрос :
Я хочу отложить выпуск старого (и больше не используемого) Экземпляр iCatalog в другой поток.
Я еще не тестировал его, но я намерен создать новый поток с :
ErazerThread.OldCatalog := Catalog; // old catalog refcount jumps to 2
Catalog := LoadNewCatalog(...); // old catalog refcount =1
ErazerThread.Execute; //just set OldCatalog to nil.
таким образом, я ожидаю, что освобождение произойдет в потоке, и мое приложение больше не
будет зависать.
Безопасно ли это (и хорошая практика)?
Есть ли у вас примеры существующего кода, который уже выполняет выпуск с помощью аналогичного метода?
Комментарии:
1. Еще одна вещь, на которую следует обратить внимание, — это возможность того, что ваш объект имеет некоторое сходство с потоком, который его создал.
2. Вы использовали профилировщик и выяснили, ПОЧЕМУ бесплатный код занимает так много времени? Одни только операции с кучей, вероятно, НЕ вызывают вашей проблемы, если вы не освобождаете 1,8 ГБ памяти, по 100 байт за раз.
3. @WarrenP Используя профилировщик выборки и завершая выпуск с помощью OutputDebugString (‘SAMPLING ON’); (и ВЫКЛЮЧЕН), я обнаружил, что 95,05% времени происходит в ntdll.dll … это не имеет для меня никакого полезного значения .. (тогда может ли анализ оставшихся 4,54% в моем исполняемом файле бытьинтересно для оптимизации?)
4. Уоррен П.: разве управление COM-памятью не медленнее, чем родной? Речь идет о распределении интерфейсов. Не знаю, насколько медленнее.
5. @DamienD: я удивлен, что выделение памяти занимает так много времени внутри ntdll.dll . Он должен сильно меняться местами? Сколько у вас физической оперативной памяти?
Ответ №1:
Я бы позволил такому блоку потока в некоторой потокобезопасной очереди (*) и отправил интерфейсы для освобождения в эту очередь, как я знаю.
Однако обратите внимание, что если освобождение затрагивает блокировку, которую использует ваш диспетчер памяти (например, глобальную блокировку heapmanager), то это бесполезно, поскольку ваш mainthread заблокируется при первом доступе к heapmanager.
С heapmanager с пулами потоков для каждого потока выделение большого количества элементов в одном потоке и освобождение его в другом потоке может помешать объединению и повторному использованию алгоритмов (небольших) блоков.
Я все еще думаю, что способ, который вы описываете, обычно звучит при правильной реализации. Но это с теоретической точки зрения, чтобы показать, что может быть ссылка из 2-го потока на основной поток через heapmanager.
(*) Самый простой способ — добавить его в tthreadlist и использовать tevent для сигнализации о том, что элемент был добавлен.
Комментарии:
1. Я понимаю вашу точку зрения, но что касается потоков и низкоуровневого управления памятью, я, хм, новичок … поправьте меня, если я ошибаюсь: глобальная блокировка heapmanager может быть вызвана потокобезопасным объектом? (я имею в виду использование критических разделов?)
2. Потокобезопасный объект передается в memorymanager при освобождении. MemoryManager может вызываться из нескольких потоков, поэтому имеет блокировки. Может быть, мне следует обобщить ответ следующим образом: «Если перемещение по дереву, подсчет ссылок и деструкторы оказываются основным фактором замедления, может помочь переход к потоку. Если это работа по освобождению в heapmanager (или вызовы COM, если они являются COM-объектами), это может быть не так »
3. попробовал. переход к потоку в моем случае не помогает (см. Мой комментарий под моим вопросом). спасибо, что объяснили, почему.
Ответ №2:
Это выглядит нормально, но не вызывайте метод потока Execute
напрямую; это запустит код объекта потока в текущем потоке вместо того, который создает объект потока. Start
Resume
Вместо этого вызовите or .