2013-04-28 6 views
1

Я создал пользовательский элемент управления, как показано ниже.Шрифт вызывает утечку GDI в пользовательском контроле

public partial class TextBoxEx : TextBox 
{ 
    public TextBoxEx() 
    { 
    InitializeComponent(); 
    Font = Utility.normalFont; 
    } 

    protected override void OnPaint(PaintEventArgs pe) 
    { 
    base.OnPaint(pe); 
    } 
} 
//A utility class to initialize font. 
class Utility 
{ 

    internal static Font normalFont = new Font("Arial", 18); 
} 

У меня есть две формы Form1 и Form2. Этот TextBoxEx добавляется в Form2. Я показываю Form2 при нажатии кнопки в Form1.

Непрерывное отображение и закрытие формы2 вызывает утечку GDI в моем приложении. После анализа с помощью инструмента обнаружения GDI (Bear.exe) обнаружено, что шрифт вызывает утечку GDI.

Мой вопрос,

  1. Почему шрифт не выделяется, даже если метод Dispose() из TextBoxEx является дозвонились. (При закрытии Form2, Dispose() метод TextBoxEx будет вызываться автоматически).
  2. Как я могу решить утечку GDI, вызванную шрифтом ?. (Font.Dispose() не может быть вызван в методе Dispose() TextBoxEx. Потому что он вызывает исключение «Параметр недействителен» в конструкторе).
+1

Шрифт не должен выпускаться, поскольку он ссылается на статическую переменную normalFont. Я не думаю, что это утечка вообще. –

+0

@Alex: Когда я прокомментирую эту строку кода «Font = Utility.normalFont;», утечка исчезнет. Я думаю, что Шрифт хранит копию, а не ссылку. Я мог бы решить проблему утечки GD, установив Font = null в методе Dispose() TextBoxEx. Но это хорошая идея? – NidhiSree

+0

Шрифт является ссылочным типом, поэтому он не копируется. Я думаю, что ваш анализатор утечек дает неверную информацию.Прочитайте ответ Ханса Пассана, вы нигде не найдете лучшего эксперта :) –

ответ

3

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

Шрифт класс трудный однако. Они не дешево для создания, Windows нужно сделать много работы, чтобы нанести на карту шрифт, который вы запрашиваете, на доступный набор шрифтов и загрузить контур TrueType. У Winforms есть решение для этого, это caches fonts. Вы понесете стоимость создания шрифта в первый раз, когда используете его. Но вы можете утилизировать его, но объект шрифта остается в кеше шрифтов. В следующий раз, когда вы создадите тот же шрифт, вы получите очень дешевую копию из кеша.

Это также проблема в WPF, тем более, что она имеет гораздо более богатую поддержку шрифтов, которая включает поддержку контуров OpenType. Он был решен другим способом, WPF использует полностью отдельный процесс для кеширования шрифтов. Работает как сервер кеша шрифтов для любого приложения WPF. Вы снова увидите этот процесс в диспетчере задач, это процесс PresentationFontCache.exe.

Anyhoo, любая программа диагностики утечек будет смущена этим кешем. Он будет думать, что ваше приложение утечки шрифтов, он видит шрифты, которые хранятся в кеше. У вас есть только настоящая утечка, когда количество используемых шрифтов растет без ограничений и, в конечном счете, приводит к сбою вашей программы. Простая проверка, квота, которую устанавливает Windows, низкая, процесс не может создать более 10 000 объектов чертежа. Поэтому вам не нужно запускать свою тестовую программу очень долго, чтобы достичь этой квоты, если у вас настоящая утечка. Вы также можете увидеть это снова в диспетчере задач. Открыть + Выбрать столбцы, поставьте галочку в поле Объекты GDI. Убедитесь, что номер вашей тестовой программы стабилен и не превышает пару сотен, дайте или возьмите.

+0

Когда я постоянно открываю и закрываю форму, счет GDI в TaskManager увеличивается на 1. Но когда я устанавливаю Font = null в методе Dispose() TextBoxEx, утечка GDI исчезает. Рекомендуется ли устанавливать шрифт как NULL в методе Dispose() элемента управления TextBox? – NidhiSree

+0

Когда я постоянно открываю и закрываю Form2, счет GDI в TaskManager продолжает увеличиваться на 1. После увеличения количества GDI до некоторого счета (70-80), он автоматически уменьшится до некоторого количества и так далее. Когда я добавляю 500 TextBoxEx в form2 и постоянно открываю и закрываю форму, счет GDI в TaskManager будет равен 504. Он не увеличивается. при установке Font = null в методе Dispose() TextBoxEx, счет GDI в TaskManager будет сброшен до 4 при закрытии формы. Рекомендуется ли устанавливать шрифт как NULL в методе Dispose() элемента управления TextBox? Или следует ли игнорировать его и доверять GC для сбора объектов GDI? – NidhiSree

+0

Я вижу нечто похожее, странное. Тем не менее, он никогда не взрывается, подсчет объектов GDI продолжает снижаться и восстанавливаться без необходимости делать что-либо в методе Dispose() или устанавливать ссылку на шрифт на null. Я сделаю еще больше копания, когда у меня будет время, но у вас, конечно, нет проблем. –

Смежные вопросы