Вопрос

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


Существует абстрактный класс StrategyEditor (производный от некоторого класса в рамках), экземпляр которого создается всякий раз, когда открывается новая форма StrategyForm.

StrategyForm (индивидуальная оконная рама) содержит StrategyEditor.
StrategyEditor содержит StrategyTab.
StrategyTab содержит StrategyCanvas.

Это небольшая часть больших классов, чтобы прояснить, что существует множество объектов, которые будут созданы, если один объект StrategyForm будет выделен в памяти во время выполнения.Мой компонент владеет всеми этими классами, упомянутыми выше, кроме StrategyForm чей код не находится под моим контролем.


Теперь во время выполнения пользователь открывает множество объектов стратегии (которые вызывают создание нового объекта StrategyForm).44 объекта стратегии, мы видим, что количество дескрипторов USER OBJECT HANDLES (здесь и далее я буду использовать UOH), созданных приложением, достигает примерно 20 000+, тогда как в реестре количество дескрипторов по умолчанию составляет 10 000. Подробнее о пользовательских объектах можно прочитать здесь. Тестирование на разных машинах показало, что количество открываемых объектов стратегии для всплывающего сообщения разное - на одном м/с если оно 44, то на другом может быть 40.

Когда мы видим всплывающее сообщение с сообщением, это означает, что приложение будет отвечать медленно.Ситуация ухудшается, если объектов становится еще меньше, а затем создание оконных рамок и последующих объектов завершается сбоем.

Сначала мы подумали, что это проблема нехватки памяти.Но потом читать больше о new на С# помог понять, что исключение будет выдано, если приложению не хватает памяти.Я считаю, что это не проблема с памятью (диспетчер задач также показывал более 1,5 ГБ доступной памяти).


Характеристики М/К
Ядро 2 Дуо 2 ГГц+
4 ГБ ОЗУ
Более 80 ГБ свободного места на диске для файла подкачки.
Набор виртуальной памяти:4000 - 6000


Мои вопросы


Вопрос 1.Похоже ли это на проблему с памятью, и я ошибаюсь, что это не так?
В2.Указывает ли это на исчерпание свободных UOH (как я думаю) и что приводит к невозможности создания дескрипторов окон?
Вопрос 3.Как мы можем избежать загрузки StrategyEditor объект (за порогом, следя за текущим использованием UOH)?(мы уже знаем, как получить количество используемых UOH, поэтому не углубляйтесь в это.) Имейте в виду, что вызов new StrategyForm() находится вне контроля моего компонента.
Вопрос 4.Я немного в замешательстве - что такое Дескрипторы пользовательских объектов точно?Говорит ли MSDN о каком-либо объекте, который мы создаем, или только о некоторых конкретных объектах, таких как дескрипторы окон, дескрипторы курсора, дескрипторы значков?
Вопрос 5.Что именно является причиной использования UOH?(почти так же, как в четвертом квартале)

Буду очень благодарен всем, кто сможет дать мне компетентные ответы.Большое спасибо!:)

[Обновлять]
Основываясь на ответе Stakx, обратите внимание, что открываемые окна будут закрыты только пользователем.Это своего рода ситуация с приложением MDI, когда открывается слишком много дочерних окон.Так, Dispose нельзя вызывать, когда захотим.

Это было полезно?

Решение

1 квартал

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

4 квартал

Я понимаю пользовательский объект быть любым объектом, являющимся частью графического интерфейса.По крайней мере, до Windows XP API Windows UI находился в USER.DLL (одна из основных DLL, составляющих Windows).По сути, пользовательский интерфейс состоит из «окон».Все элементы управления, такие как кнопки, текстовые поля, флажки, внутри представляют собой одно и то же, а именно «окна».Чтобы создать их, вы должны вызвать функцию Win32 API. CreateWindow.Затем эта функция вернет дескриптор созданного «окна» (элемент пользовательского интерфейса или «пользовательский объект»).

Поэтому я предполагаю, что дескриптор пользовательского объекта — это дескриптор, возвращаемый этой функцией.(Winforms основан на старом API Win32 и поэтому будет использовать CreateWindow функция.)

2 квартал

Действительно, вы не можете создать столько элементов управления пользовательского интерфейса, сколько захотите.Все эти дескрипторы, полученные через CreateWindow в какой-то момент должен быть освобожден.В Winforms самый простой и безопасный способ сделать это — использовать using заблокировать или позвонив Dispose:

using (MyForm form = new MyForm())
{
    if (form.ShowDialog() == DialogResult.OK) ...
}    

В принципе, все System.Windows.Forms.Control возможно Disposeд., и их следует утилизировать.Иногда это делается автоматически, но не стоит на это полагаться.Всегда Dispose элементы управления вашего пользовательского интерфейса, когда они вам больше не нужны.

Обратите внимание на Dispose для модальных и немодальных форм:

  • Модальные формы (показаны с ShowDialog) являются нет автоматически удаляются.Вам придется сделать это самостоятельно, как показано в примере кода выше.
  • Немодальные формы (показаны с Show) удаляются автоматически, поскольку вы не можете контролировать, когда он будет закрыт пользователем.Нет необходимости явно вызывать Dispose!

Q5

Каждый раз, когда вы создаете объект пользовательского интерфейса, Winforms внутренне выполняет вызовы CreateWindow.Вот как распределяются ручки.И они не освобождаются до соответствующего вызова DestroyWindow сделан.В Winforms этот вызов запускается через Dispose метод любой System.Windows.Forms.Control. (Примечание:Хотя я в этом совершенно уверен, на самом деле я немного догадываюсь.Возможно, я не на 100% прав.Взглянув на внутреннее устройство Winforms с помощью Reflector, можно раскрыть правду.)

3 квартал

Предполагая, что ваш StrategyEditor создает огромную кучу элементов управления пользовательского интерфейса, я не думаю, что вы можете многое сделать.Если вы не можете упростить этот элемент управления (с учетом количества создаваемых им дочерних элементов управления), то, похоже, вы застряли в той ситуации, в которой находитесь.Ты просто не мочь создавать бесконечное количество элементов управления пользовательского интерфейса.

Однако вы можете отслеживать, сколько StrategyEditorоткрываются в любой момент (увеличивайте счетчик всякий раз, когда он создается, и уменьшайте его всякий раз, когда он закрывается - вы можете отслеживать последнее, используя FormClosing/FormClosed событие формы или в Dispose метод контроля).Тогда можно было бы ограничить количество одновременно открываемых StrategyEditors до фиксированного числа, скажем, 5.Если предел превышен, вы можете создать исключение в конструкторе, чтобы экземпляры больше не создавались.Конечно, я не могу сказать, StrategyForm собирается обработать исключение из вашего StrategyEditor конструктор ну...

public class StrategyEditor : ...
{
    public StrategyEditor()
    {
        InitializeComponent();

        if (numberOfLiveInstances >= maximumAllowedLiveInstances)
            throw ...;
        // not a nice solution IMHO, but if you've no other choice...
    }
}

В любом случае ограничение количества экземпляров StrategyEditorМне это кажется временным решением и не решит реальную проблему.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top