2014-02-07 6 views
0

У нас есть приложение .net в C#, которое позволяет пользователям на карте домена пользователям/ролям в другом домене.Счетчик объектов GDI 10k

На панели отображения свойств (которая представляет собой просто форму, показанную в виде диалога в основной форме) есть два списка - 1 для исходного домена, а другой для всех ранее выбранных целевых доменов. Listview заполняется пользователями и группой - по одной строке для каждого пользователя/группы. У нас есть значок в каждой строке, чтобы различать пользователя и группу.

Все было в порядке, до недавнего времени один из наших клиентов столкнулся с ситуацией, когда нет. из дескрипторов GDI, созданных нашим приложением, пересек 10k - это верхний предел возможного количества ручек, которые могут быть созданы процессом в системе Windows. Итак, теперь мы думаем о том, как мы можем использовать, чтобы уменьшить количество созданных ручек. Вот несколько вопросов, на которые мы просто хотим быть уверены. Какой из них создать новую ручку (мы подозреваем, все из них):

1)

this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 14F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(177))); 

2)

this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); 

3)

this.label2.Text = resources.GetString("label2.Text"); 

Пожалуйста, не позаботьтесь о форматировании вопроса и сообщите мне, если какая-либо дополнительная информация требуется для соответствующего заключения.

Что мы можем сделать, чтобы уменьшить число. созданных ручек? Каковы правильные способы избежать такого сценария? Могут ли ручки быть убиты явно, чтобы уменьшить количество (просто говоря)? Любые предложения или вещи, о которых нужно позаботиться, оцениваются. Благодарю.

Кроме того, мы в эту строку кода:

this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); 

Итак, как мы высвободит DC и Bitmaps обрабатывает?

Screenshot from GDIView

+0

Третий не создает ручку. Первые два делают –

+0

Получите копию [Process Explorer] (http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx) и проверите ручки с видом ручек. Тогда вы сейчас начнете работать. Удачи. :) –

+0

Спасибо, Шрирам. Я использовал GDIView и добавил скриншот, а также отредактировал мой вопрос. Что вы предлагаете сейчас? – MrClan

ответ

0

Основная причина заключалась в том, что форма была инициализирована много раз, чем мы ожидали, и ImageList был сгенерирован в метод InitializeComponent() формы. Мы просто сделали это static и разделили тот же самый ImageList во всех инициализированных экземплярах этой формы. Это контролировало количество создаваемых экземпляров GDI. Нам не пришлось называть DeleteObject() на изображениях.

Первоначально мы пытались это, но, это не реальное решение, которое мы выяснили позже

Модификация показано ниже, кажется, поставить проверки на обоих, Bitmap ручки, а также постоянного тока (DeviceContext) ручками , и решает проблему в моем сценарии. Я сделал вызов функции WinAPI DeleteObject() для каждого изображения в экземпляре ImageList внутри метода(), форма в Dispose, который после модификации теперь выглядит, как показано ниже:

[System.Runtime.InteropServices.DllImport("gdi32.dll")] 
public static extern bool DeleteObject(IntPtr hObject); 

protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      listViewMapping.Clear(); 
      listBoxPropertiesA.Items.Clear(); 
      listBoxPropertiesB.Items.Clear(); 

      if (imageList1 != null) 
      { 
       foreach (var img in imageList1.Images) 
       { 
        DeleteObject(((System.Drawing.Bitmap)img).GetHbitmap()); 
       } 
       imageList1.Dispose(); 
       imageList1 = null; 
      } 

      if (components != null) 
      { 
       components.Dispose(); 
       //DeleteObject(); 
      } 
     } 
     base.Dispose(disposing); 
    } 

6

Да, ваша программа просачивается объекты System.Drawing. Каждый счет, показанный для «Bitmap», является объектом Image или Bitmap в вашей программе, каждый подсчет для «DC» (Device Context) является объектом Graphics в вашей программе.

Эти классы реализуют IDisposable, вы должны вызвать их метод Dispose(), когда вы больше не используете их. Забыть сделать это - очень общий надзор. Поскольку счетчик DC почти такой же, как и битмап-счет, у вас есть довольно хороший намек на то, где начать искать отсутствующие вызовы Dispose() или с помощью операторов, что объект Bitmap и Graphics должен быть довольно близко друг к другу ,

Кроме того, есть сильный намек на то, что поток финализатора в вашей программе не работает достаточно часто, чтобы вы не попали в неприятности. Простое объяснение этого состоит в том, что вы просто не выделяете достаточно объектов, чтобы запускать сборку мусора. Это не совсем необычно, классы Graphics и Bitmap - очень маленькие классы, которые сами по себе никогда не являются достаточными для запуска GC. Поэтому, если ваша программа тяжелая, но не тяжелая, или данные хранятся неуправляемым кодом, например, классы в System.DirectoryServices, тогда GC не ударяет достаточно часто.

Сценарий сумасшедшего дня состоит в том, что поток финализатора сломан и заблокирован. Очень трудно заметить это без неуправляемого отладчика, кроме того, что вы заметили этот точный вид утечки ресурсов. И легко упускать из виду quirk, требуется две секунды, чтобы ваша программа перестала работать, когда вы закрываете главное окно. Тупик в потоке финализатора обычно вызван проблемой потоковой передачи, особенно с объектами COM. Как и те, которые используются в System.DirectoryServices. Необходимо включить неуправляемую отладку и включить сервер Microsoft Symbol, чтобы увидеть, что он заблокирован в трассировке стека.

Надеюсь, что дело не в этом. Посмотрите, что делает GC, запустив Perfmon.exe. Щелкните правой кнопкой мыши график и добавьте категорию «# Gen 0 Collections» из категории .NET CLR Memory для вашей программы. С ожиданием, что он не будет увеличиваться при постоянном клипе.

Если вы не можете найти ошибку или он находится в коде, который вы не можете исправить, возможно, вам придется помочь и заставить сборщика мусора работать. Вы можете использовать, скажем, таймер и вызывать GC.Collect() в обработчике событий Tick. Или, желательно, любое другое место в ваш код, в котором вы можете разумно разместить счетчик, который является представительным для количества пропущенных объектов Graphics/Bitmap.

+0

Спасибо за ваш ответ. Я вызвал DeleteObject() на каждом изображении в ImageStream внутри метода Dispose() формы - точно так же, как показано на странице msdn, и это, похоже, решило проблему. Теперь счетчик остается в пределах 200. Я ожидал этого чтобы проверить количество бит Handmap. Но ** DC count ** также находится под лимитом, и я не могу найти объяснения. Что бы вы сказали, возможная причина этого могла быть? – MrClan

+0

DeleteObject() - это функция winapi, она не принадлежит программе Winforms. Я не могу комментировать код, который я не вижу, и это не имеет смысла. –

+0

Извините, что не ясны. Ниже приведен ответ, который я добавил, который точно показывает, как я вызвал и использовал функцию DeleteObject() в моем коде. – MrClan

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