Подтвердить что ты не робот

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);
}
4b9b3361

Ответ 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 черные прямоугольники не были частью описания.