Это проблема приложения WinForm MDI (.net framework 3.0). Это будет описано в C #. Извините, это немного долго, потому что я стараюсь сделать вещи как можно яснее.
У меня есть приложение MDI. В какой-то момент я обнаружил, что одна дочерняя форма MDI никогда не выпускается. Есть меню, которое создает дочернюю форму MDI и показывает ее. Когда дочерняя форма MDI закрыта, она должна быть уничтожена, а взятая ею память должна быть возвращена в .net. Но, к моему удивлению, это не так. Все экземпляры дочерней формы MDI хранятся в памяти. Это, очевидно, «утечка памяти». Ну, это не настоящая утечка в .net. Просто я думаю, что закрытая форма должна быть мертвой, но каким-то образом есть хотя бы одна неизвестная ссылка из внешнего мира, которая все еще связана с закрытой формой.
Я прочитал несколько статей в Интернете. Некоторые говорят, что, когда дочерняя форма MDI закрывается, я должен отключить все обработчики событий, иначе некоторые обработчики событий могут поддерживать мою форму в живых. Некоторые говорят, что DataBindings следует очистить перед закрытием формы, иначе DataBindings добавит ссылки на некоторые глобальные Hashtable и, таким образом, сохранит мою форму живой.
Моя форма содержит довольно много вещей. Множество обработчиков событий, много DataBindings, много BindingSources и несколько подозрительных элементов управления, содержащих пользовательский элемент управления и HelpProvider. Я создаю большой метод, который соединяет все обработчики событий со всеми соответствующими элементами управления, очищаю все DataBindings и DataSources. HelpProvider и пользовательские элементы управления расположены аккуратно.
В конце я обнаружил, что мне не нужно очищать привязки данных и источники данных. Обработчики событий определенно вызывают проблему. И структура формы MDI также чему-то способствует.
Во время моих экспериментов я обнаружил, что если вы создадите дочернюю форму MDI, даже если вы закроете ее, в памяти все равно останется один экземпляр. Ссылка из PropertyStore основной формы. Это означает, что если основная форма не закрыта (приложение закрывается), в памяти всегда будет один экземпляр дочерней формы MDI. Хорошей новостью является то, что независимо от того, сколько раз вы открываете и закрываете дочернюю форму, будет только один экземпляр, а не большая «утечка».
Когда дело доходит до обработчиков событий, все становится сложнее. Я должен обратиться к этому, все обработчики событий в моей форме являются анонимными обработчиками событий. Вот пример кода:
//On MDI child form's design code...
Button btnSave = new Button();
btnSave.Click += new System.EventHandler(btnSave_Click);
Где btnSave_Click
также метод в дочерней форме MDI. Вышеуказанное всегда относится к различным элементам управления и различным типам событий. Для меня это двунаправленная круговая ссылка. btnSave хранит ссылку на дочернюю форму MDI через обработчик событий. Дочерняя форма MDI содержит ссылку на экземпляр btnSave. Мне опять же, такая двунаправленная круговая ссылка не должна создавать проблем для сборщика мусора .net. Это означает, что мне не нужно явно связывать событие при удалении формы:
btnSave.Click -= btnSave_Click;
Но правда не в этом. Для некоторых обработчиков событий они безопасны. Игнорирование их не вызывает дублирования экземпляра. Для некоторых других обработчиков событий они будут приводить к тому, что один экземпляр останется в памяти (эффект, аналогичный структуре формы MDI, но на этот раз вызванный зависанием обработчиков событий). Для некоторых других обработчиков событий они будут вызывать каждый экземпляр, открытый в памяти. Я полностью запутался в различиях между этими тремя типами обработчиков событий. Элементы управления создаются таким же образом, а событие прикрепляется таким же образом. В чем разница? (Не говорите мне, что методы обработки событий имеют значение.) У кого-нибудь есть опыт этого проводного сценария и есть ответ для меня? Большое спасибо.
Так что теперь, из-за проблем безопасности, мне придется отключить все обработчики событий при удалении формы. Это будет длинный список аналогичного кода для каждого элемента управления. Существует ли общий способ удаления событий из элементов управления рекурсивным способом с использованием отражения? Как насчет проблемы с производительностью?
Это конец моей истории, и я все еще в центре моей проблемы. За любую помощь, я благодарю вас.