Skip to main content
All docs
V25.1
  • Prevent Memory/Resource Leaks

    • 5 minutes to read

    The application allocates memory for each created object. If these objects are never disposed of, memory usage gradually grows. This may impact performance or cause a crash.

    This help topic lists best practices to prevent leaks and ensure optimal memory usage.

    Overview

    Explicitly Dispose of IDisposable Objects

    Classes that implement the IDisposable interface (Stream, Graphics, File, etc.) require explicit disposal.

    Call the Dispose() method before you release the last reference to such an object. If the object is declared in a method, wrap its declaration in a using statement to dispose of the object automatically.

    using(var ms = new MemoryStream(photoBytes)) {
        // Use the object
    }
    

    Unsubscribe From Events

    When an object subscribes to another object’s event, the publisher (the object that raises the event) holds a strong reference to the subscriber (the event handler’s target). Even if the subscriber object is no longer needed, the garbage collector cannot dispose of it because the publisher still references it through the event delegate list.

    Over time, repeated event subscriptions without a proper unsubscription can accumulate, increase memory usage, and cause an OutOfMemoryException.

    Unsubscribe from events to remove unnecessary references and prevent possible leaks.

    Example

    If you subscribe to an event within a frequently executed method, unsubscribe before the method is executed again.

    For example, you subscribe to a popup form event in a PopupBaseEdit.Popup event handler. The Popup event fires after a popup window is opened. Unsubscribe from the event when the popup is closed:

    private void SearchLookUpEdit1_Popup(object sender, EventArgs e) {
        var edit = sender as SearchLookUpEdit;
        var popupForm = edit.GetPopupEditForm();
        popupForm.KeyUp += PopupForm_KeyUp;
    }
    
    private void SearchLookUpEdit1_Closed(object sender, DevExpress.XtraEditors.Controls.ClosedEventArgs e) {
        var edit = sender as SearchLookUpEdit;
        var popupForm = edit.GetPopupEditForm();
        popupForm.KeyUp -= PopupForm_KeyUp;
    }
    

    Tip

    Refer to the following Microsoft blog post for more information: Dive into Event Handler Leak Insights.

    Explicitly Dispose of Modal Forms

    Closed modal forms are hidden but not disposed of. If you do not need to restore hidden modal forms, call the Dispose() method. You can also declare a form in a using statement.

    using (var dialogForm = new MyDialogForm()) {
        // Configure the form
        dialogForm.Show();
        // Read the result
    }
    

    Refer to the following Microsoft Learn help topic for more information: Form.ShowDialog Method.

    Manage Object Lifetime

    Static objects and all objects they reference remain in memory for the application’s lifetime.

    Similarly, objects declared at the level of a long-lived object remain in memory until the container’s lifetime ends. For example, a variable at the main form level remains in memory until the application is closed.

    The following recommendations help ensure that objects do not remain in memory longer than needed:

    • Declare only global, reusable objects as static.

    • Do not store large, disposable objects at the level of a long-lived object.

    Font Management

    A Font is an IDisposable object (requires explicit disposal). Repeated creation and disposal of a Font object in frequently raised events is resource-consuming.

    Consider the following best practices that help reduce font-related memory consumption:

    • Do not create a new font each time the font changes. Use AppearanceObject.FontStyleDelta and AppearanceObject.FontSizeDelta to modify existing fonts:

      private void GridView_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventArgs e) {
          if (e.RowHandle % 2 == 0) {
              e.Appearance.FontStyleDelta = FontStyle.Italic;
              e.Appearance.FontSizeDelta = 5;
          }
      }
      
    • If a new font is required (for example, you change the FontFamily), create it once and reuse it:

      public Form1() {
          InitializeComponent();
          myFont = new Font("Arial", 15);
          // ...
      }
      // ...
      Font myFont;
      
      private void GridView_RowCellStyle(object sender, DevExpress.XtraGrid.Views.Grid.RowCellStyleEventArgs e) {
          if (e.RowHandle % 2 == 0)
              e.Appearance.Font = myFont;
      }
      

    Safe Creation of Drawing Objects

    Frequent creation of brushes and pens for custom drawing causes excessive Graphics Device Interface (GDI) allocations, slows down rendering, and forces the garbage collector to run more often.

    Use the following techniques to minimize memory allocation:

    • Use GraphicsCache methods (for example, FillRectangle) to obtain brushes and pens. GraphicsCache maintains an internal cache of pens/brushes. Pens with the same color/width/style are reused (fewer objects are created). GraphicsCache also manages disposal of pens and brushes.

      The following code snippet fills a rectangle with red:

      using DevExpress.XtraGrid.Views.Base;
      using DevExpress.Utils.Drawing;
      
      private void GridView_CustomDrawGroupPanel(object sender, CustomDrawEventArgs e) {
          e.Cache.FillRectangle(Color.Red, e.Bounds);
          // ...
      }
      
    • If you need to create Drawing/Graphics objects outside of painting methods, initialize the object in a using statement:

      using (GraphicsCache cache = grid.CreateGraphicsCache()) {
          view.Appearance.Row.CalcTextSizeInt(cache, "text", 75);
      }
      
    See Also