System.Drawing Out of Memory Exception On Main() Method - С#
Моя программа - это CRM, я использовал панель Ribbon Rad, так много кнопок с изображениями, RadGridView (некоторые из которых содержат изображения) и многие другие элементы управления, содержащие изображения. Это родительская/дочерняя программа mdi.
![Только пример RibbonBar]()
Во многих случаях при загрузке дочернего mdi или работе с некоторыми видами сетки программа зависает и дает мне эту ошибку:
OutOfMemoryException occurred in System.Drawing.dll
Я пробовал GC.Collect()
на определенных участках, но не добился успеха. Для установки изображений нет кода! например, для установки изображения для кнопки я использовал свои свойства в visual studio. Я установил все остальные управляющие изображения таким образом, используя панель свойств в визуальном режиме.
![введите описание изображения здесь]()
и это некоторые коды дизайнеров, относящиеся к чертежу:
btnCustomerList.Image = global::MyApp.Properties.Resources.CustomerList32;
gridViewCommandColumn1.Image = global::MyApp.Properties.Resources.ViewShop32;
и Когда ошибка возникает после работы с приложением, она появится в Program.cs
и в строке Application.Run(new MainForm());
:
static void Main()
{
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", AppDomain.CurrentDomain.BaseDirectory + "\\Settings.config");
bool ok;
Mutex m = new Mutex(true, WindowsIdentity.GetCurrent().Name.ToString().Split('\\')[1] + "MyApp", out ok);
if (ok)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// The Error will cause HERE
Application.Run(new MainForm());
GC.KeepAlive(m);
}
else
Application.Exit();
}
MainForm
является родителем mdi, который содержит Ribbon Bar.
и это полная трассировка стека:
at System.Drawing.Image.FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
at System.Drawing.Image.FromHbitmap(IntPtr hbitmap)
at System.Drawing.Icon.ToBitmap()
at System.Windows.Forms.ThreadExceptionDialog..ctor(Exception t)
at System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
at System.Windows.Forms.Control.WndProcException(Exception e)
at System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at MyApp.Program.Main() in d:\\MyApp\\Application\\MyApp\\Program.cs:line 36"
UPADTED:
код для вызова mdi-children
, нажав на кнопки панели ленты, находится здесь:
private void btnCustomerList_Click(object sender, EventArgs e)
{
OpenForm(new FormCustomerList(), "Customer List");
}
private void btnCustomerRelated_Click(object sender, EventArgs e)
{
OpenForm(new FormCustomerRelated(), "Customer Related");
}
и здесь OpenForm
метод:
private void OpenForm(Form formType, string Caption)
{
foreach (Form nform in Application.OpenForms)
{
if (nform.GetType() == formType.GetType())
{
nform.Activate();
return;
}
}
this.MdiChildren.OfType<Form>().ToList().ForEach(x => x.Dispose());
GC.Collect();
Form form = formType;
form.MdiParent = this;
form.Dock = DockStyle.Fill;
form.Show();
this.Text = Caption;
}
и в каждом конструкторе дочерней формы mdi, после InitializeComponent();
я написал также GC.Collect();
. Но, как сказано в комментариях, диспетчер задач GDI objects
будет увеличиваться и увеличиваться до 10000
объектов, а затем приложение будет аварийно.
ОБНОВЛЕНО: САМЫЙ НОМЕР
Кажется, я нашел часть, которая вызывает наибольшее GDI objects
. В каждой форме есть некоторые элементы управления, такие как текстовые поля, выпадающий список и т.д. Я установил для них некоторые правила, например, если пользователь вводит текстовое поле, его задний цвет должен быть желтым, а после отпуска он должен быть белым снова. Таким образом, существует основной метод, который я вызываю в форме загрузки для грамотности через все элементы управления и поиска целевых и добавления, например, ввода и исключения событий с определенными правилами. что-то вроде этого:
private void FormCustomerList_Load(object sender, EventArgs e)
{
ClassCRMControls.AddEventHandler(this);
}
и внутри ClassCRMControls
class:
public static void AddEventHandler(Control parent)
{
foreach (Control c in parent.Controls)
{
if (c.GetType() == typeof(RadTextBox))
{
c.Enter += new EventHandler(ClassCRMControls.EnterEvent);
c.Leave += new EventHandler(ClassCRMControls.LeaveEvent);
}
else
AddEventHandler(c);
}
}
private static void EnterEvent(object sender, EventArgs e)
{
(sender as RadTextBox).TextBoxElement.TextBoxItem.BackColor = Color.FromArgb(255, 251, 147);
}
private static void LeaveEvent(object sender, EventArgs e)
{
(sender as RadTextBox).TextBoxElement.TextBoxItem.ResetValue(LightVisualElement.BackColorProperty, ValueResetFlags.Local);
}
Ответы
Ответ 1
Я нашел источник проблемы, и это был настраиваемый анимированный курсор, который я использовал для сеток и других элементов управления. Я инициализирую его следующим образом:
this.Cursor = ClassObjects.CreateAnimatedCursor("C:\\aniCur.ani"));
Так как я загружал этот курсор из файла каждый раз, когда я его использовал, все больше и больше GDI Objects
создавалось.
Итак, я объявил public static cursor
main() соответствующей формы следующим образом:
public static Cursor animCur = ClassObjects.CreateAnimatedCursor("C:\\aniCur.ani"));
а затем всякий раз, когда мне нужно использовать этот курсор, я просто ссылаюсь на этот объект public static cursor
в форме.
this.Cursor = MainForm.animCur;
That It:)
Как я его нашел? Я просто пытаюсь удалить (комментируя) некоторые коды, которые я подозревал, а затем я проверил GDI Objects
в диспетчере задач. После некоторого тестирования стало очевидным, что бесконечная загрузка новых объектов курсора вызывала проблему.
Ответ 2
В OutOfMemoryExceptions может быть несколько причин. Я обсуждал 6 из них в другом вопросе.
В этом случае после комментариев и редактирования стало ясно, что также возникают проблемы GDI. Вы можете обнаружить эти проблемы, указав дополнительный столбец в диспетчере задач:
![Объекты GDI, указанные в диспетчере задач]()
GDIView - гораздо лучшее приложение для анализа GDI Leak, потому что оно также сообщает вам тип дескриптора GDI, который потерялся. Он также имеет абсолютные и относительные счетчики, поэтому вы можете видеть, как многие из них теряются во время определенного действия.
![Детали GDIView]()
Количество дескрипторов GDI может быть настроено в реестре. Не используйте это как постоянное решение. Вместо этого, с дополнительной информацией из GDIView, найдите фрагмент кода, который утечки объекта GDI.
Когда вы сталкиваетесь с ограничениями дескрипторов GDI, приложение обычно начинает плохо выглядеть: вещи больше не раскрашены, и вы получаете черные прямоугольники в некоторых местах. Однако это поведение не обязательно. В случае OP черные прямоугольники не были частью описания.