2017-11-02 28 views
13

Chương trình của tôi là CRM, tôi sử dụng Rad Ribbon Bar, nhiều nút với hình ảnh, RadGridView (một số cột chứa hình ảnh) và rất nhiều điều khiển khác chứa hình ảnh. Đó là một chương trình mẹ/con mdi.System.Drawing Out of Memory Exception On Main() Phương thức - C#

Just an Example of RibbonBar

Trong rất nhiều trường hợp khi tải một đứa trẻ MDI hoặc làm việc với một số lưới xem chương trình sẽ treo và đưa cho tôi lỗi này:

OutOfMemoryException occurred in System.Drawing.dll 

tôi đã cố gắng GC.Collect() trên các bộ phận nhất định, nhưng không thành công . Để thiết lập hình ảnh không có mã! ví dụ để thiết lập một hình ảnh cho một nút, tôi đã sử dụng các thuộc tính của nó trong studio trực quan. Tôi đã đặt Tất cả các hình ảnh điều khiển khác theo cách này bằng cách sử dụng bảng thuộc tính ở chế độ trực quan.

enter image description here

và đây là một số mã thiết kế liên quan đến bản vẽ:

btnCustomerList.Image = global::MyApp.Properties.Resources.CustomerList32; 

    gridViewCommandColumn1.Image = global::MyApp.Properties.Resources.ViewShop32; 

và Khi Các lỗi được đưa ra sau một thời gian làm việc với các ứng dụng, nó sẽ xuất hiện trong Program.cs và trong dòng 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 là cha mẹ mdi có chứa thanh Ribbon. và đây là Full stack trace:

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:

mã để gọi mdi-children bằng cách nhấp vào nút thanh ribbon là ở đây:

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"); 
} 

và đây là OpenForm phương pháp:

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; 
} 

và trong mọi mdi nhà xây dựng biểu mẫu của trẻ em, sau InitializeComponent(); Tôi cũng đã viết GC.Collect();. Nhưng như đã nói trong phần nhận xét, GDI objects trong trình quản lý tác vụ sẽ tăng và tăng cho đến 10000 đối tượng và sau đó ứng dụng sẽ gặp sự cố.

UPADTED: Vấn đề MOST

Có vẻ như tôi đã tìm thấy phần gây nhất GDI objects. Trong mọi hình thức có một số điều khiển như hộp văn bản, danh sách thả xuống vv. Tôi đã thiết lập một số quy tắc cho họ, ví dụ nếu người dùng nhập vào một hộp văn bản, màu sắc của nó phải là màu vàng và sau khi rời khỏi nó phải là màu trắng một lần nữa. Vì vậy, có một phương pháp chính mà tôi gọi trong tải hình thức để biết chữ thông qua tất cả các điều khiển và tìm thấy những mục tiêu và thêm ví dụ nhập và để lại các sự kiện với các quy tắc được xác định. một cái gì đó như thế này:

private void FormCustomerList_Load(object sender, EventArgs e) 
{ 
    ClassCRMControls.AddEventHandler(this); 
} 

và bên ClassCRMControls lớp:

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); 
} 
+0

Ghi nhật ký ngăn xếp đầy đủ của ngoại lệ này, có thể nó sẽ cung cấp một số đầu mối. – Evk

+2

Hmya, chương trình có một rò rỉ xử lý xấu. Nó là xấu như vậy mà ngay cả hộp thoại ngoại lệ không thể được hiển thị nữa. Đó là điều bạn có thể thấy trong Task Manager, tab Processes. Thêm cột cho các đối tượng GDI, bạn sẽ thấy nó tăng dần và chương trình kết thúc khi đạt đến 10000. Không ai giành được bất kỳ giải thưởng nào để không xử lý những hình ảnh này, nhưng nó không gây tử vong. Bạn đã nói rằng bạn đã thử GC.Collect(), nó không giúp đỡ sau đó thread finalizer có lẽ là bế tắc. Bật gỡ lỗi không được quản lý và tìm hiểu xem nó đang làm gì. –

+1

Ngoài ra hãy nhìn vào cột USER Objects, rò rỉ đó là một lỗi truyền thống khác trong Winforms gây ra bằng cách sử dụng Controls.Clear() hoặc Remove(). –

Trả lời

5

tôi đã tìm thấy nguồn gốc của vấn đề và đó là phong tục hoạt hình con trỏ tôi sử dụng cho lưới và điều khiển khác quá.Tôi khởi tạo nó như thế này:

this.Cursor = ClassObjects.CreateAnimatedCursor("C:\\aniCur.ani")); 

Kể từ khi tôi nạp con trỏ này từ tập tin mỗi khi tôi sử dụng nó trong bất kỳ cách nào, ngày càng nhiều GDI Objects đã tạo ra.

Vì vậy, tôi tuyên bố một public static cursor hàm main() có dạng tương ứng như thế này:

public static Cursor animCur = ClassObjects.CreateAnimatedCursor("C:\\aniCur.ani")); 

và sau đó bất cứ khi nào tôi cần phải sử dụng con trỏ này tôi chỉ tham khảo đối tượng này public static cursor từ biểu mẫu.

this.Cursor = MainForm.animCur; 

Đó là nó :)

Làm sao tôi tìm thấy nó? Tôi chỉ cố gắng loại bỏ (bình luận) một số mã mà tôi nghi ngờ họ, sau đó tôi đã kiểm tra GDI objects trong trình quản lý tác vụ. Sau một số thử nghiệm, nó trở nên rõ ràng rằng việc tải vô tận các đối tượng con trỏ mới đã gây ra vấn đề.

+3

Đây không phải là một câu trả lời rất hữu ích. Chắc chắn các độc giả trong tương lai của Q + A này sẽ không có cùng một vấn đề chính xác và muốn biết cách bạn phát hiện ra nguyên nhân của sự rò rỉ xử lý này. Và xem xét để chỉ làm điều này một cách chính xác để GC * có thể * chính xác tránh rò rỉ. Mã mẫu [có tại đây] (https://stackoverflow.com/a/4306984/17034), việc hack bằng trường "ownHandle" sẽ xử lý nó. –

+1

Đối với người đọc trong tương lai OP câu trả lời đã chỉnh sửa để bao gồm phân tích đối tượng GDI của mình. Hans đã thảo luận về nó [ở đây] (https://stackoverflow.com/a/8306253/495455), quan sát Đếm GDI trong khi bạn sử dụng ứng dụng. Có thêm thông tin và các bước về cách thực hiện điều này [ở đây] (https://stackoverflow.com/a/40232021/495455) –

+1

Tôi không đồng ý, đây là câu trả lời hữu ích vì nó cho người đọc trong tương lai biết rằng "OutOfMemoryException" có nhiều nguồn hơn cho lỗi hơn * chỉ * trong điều kiện bộ nhớ. Ở đây có một sự rò rỉ của các xử lý GDI, và nếu điều này cuối cùng gây ra cùng một ngoại lệ thì đó là một tình huống hữu ích để mô tả cho bạn. Tuy nhiên, có các bài đăng Hỏi & đáp khác ở đây trên SO để nêu chi tiết những điều này chi tiết hơn. Mặc dù điều này không làm mất hiệu lực câu hỏi này và câu trả lời của nó, có lẽ nó có giá trị để đóng nó như là một bản sao? –

3

Có thể có nhiều lý do cho OutOfMemoryExceptions. Tôi đã thảo luận 6 trong số họ in another question.

Trong trường hợp này, sau khi nhận xét và chỉnh sửa, rõ ràng là vấn đề GDI cũng xảy ra. Bạn có thể phát hiện những vấn đề này bằng cách hiển thị một cột bổ sung trong nhiệm vụ quản lý:

GDI objects shown in Task Manager

GDIView là một ứng dụng tốt hơn để phân tích GDI rò rỉ, bởi vì nó cũng cho bạn biết các loại tay cầm GDI rằng đã bị mất. Nó cũng có các bộ đếm tuyệt đối và tương đối, vì vậy bạn có thể thấy có bao nhiêu trong số chúng bị mất trong một hành động cụ thể.

GDIView details

Số lượng GDI xử lý can be configured in Registry. Không sử dụng như một giải pháp lâu dài. Thay vào đó, với thông tin bổ sung từ GDIView, hãy tìm đoạn mã rò rỉ đối tượng GDI.

Khi bạn chạy vào giới hạn xử lý GDI, ứng dụng thường bắt đầu trông xấu: mọi thứ không được vẽ nữa và bạn sẽ nhận được hình chữ nhật màu đen ở một số nơi. Tuy nhiên, hành vi này là không cần thiết. Trong trường hợp của OP, hình chữ nhật màu đen không phải là một phần của mô tả.

Các vấn đề liên quan