Возможно ли, что Krypton (библиотека Winforms) имеет проблемы с утечкой памяти - PullRequest
4 голосов
/ 27 мая 2011

В настоящее время я отлаживаю большое приложение Winforms, у которого есть проблемы с утечкой памяти. Я использую профилировщик памяти .NET и до сих пор мне удавалось найти некоторые из этих утечек и устранить их. Но теперь я столкнулся с проблемой, в которой я не уверен, что это проблема, и если она есть, я не знаю, как ее решить.

После запуска моего приложения в течение примерно 1 минуты (что не так уж много, учитывая, что обычные пользователи могут использовать его часами), профилировщик памяти .NET показывает мне около 100-200 экземпляров различных элементов управления из набора инструментов Krypton, и это число увеличивается, если я продолжаю идти (они никогда не собираются мусором, потому что кажется, что на них все еще есть ссылки). Теперь, если я проверю корневой путь этих экземпляров, и они все будут выглядеть так:

Root path for Krypton ViewManager

Я не знаю, где искать в моем коде правильную разыменование этих экземпляров, когда они больше не нужны, так как я не знаю, что все еще ссылается на элемент управления. Я знаю место, где создается KryptonButtonEx, и насколько я понимаю, ViewManager создается этой кнопкой, но все же я не понимаю, что я могу с этим поделать. Для тех, кто заинтересован, код для создания кнопки такой:

        KryptonButton newControlButton = new KryptonButton();
        newControlButton.Tag = mtActivityControl;
        newControlButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
        newControlButton.AutoSize = true;
        newControlButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
        newControlButton.ButtonStyle = ComponentFactory.Krypton.Toolkit.ButtonStyle.ListItem;
        newControlButton.Location = new System.Drawing.Point(3, 3);
        newControlButton.Name = string.Format("controlButton{0}", mtActivityControl.SymbolicName);
        newControlButton.Size = new System.Drawing.Size(96, 23);
        newControlButton.StateCommon.Content.Image.ImageH = ComponentFactory.Krypton.Toolkit.PaletteRelativeAlign.Near;
        newControlButton.StateCommon.Content.ShortText.TextH = ComponentFactory.Krypton.Toolkit.PaletteRelativeAlign.Near;
        newControlButton.TabIndex = 5;

        StringBuilder buttonText = new StringBuilder();
        buttonText.Append(Path.GetFileName(mtActivityControl.ControlName));
        /*if (mtActivityControl.SymbolicName.Length != 0)
        {
            buttonText.Append(" (");
            buttonText.Append(mtActivityControl.SymbolicName);
            buttonText.Append(")");
        }*/

        newControlButton.Text = buttonText.ToString();
        newControlButton.Values.ExtraText = "";
        newControlButton.Values.Image = null;
        newControlButton.Values.ImageStates.ImageCheckedNormal = null;
        newControlButton.Values.ImageStates.ImageCheckedPressed = null;
        newControlButton.Values.ImageStates.ImageCheckedTracking = null;
        newControlButton.Values.Text = buttonText.ToString();
        newControlButton.Click += new System.EventHandler(this.controlsButton_Click);

и, хотя в моих исследованиях нет необходимости, я отцепил подобное событие в функции Dispose:

newControlButton.Click -= new System.EventHandler(this.controlsButton_Click);

Итак, мой вопрос:

Возможно ли, что сам Криптон хранит ссылку на мои элементы управления, что приводит к тому, что некоторая память не освобождается (что может быть хорошо, если это ограниченный объем памяти, используемый для хранения пула объектов или чего-то в этом роде, но это может быть проблема, если это неконтролируемая утечка памяти)? Если это не от Криптона, есть ли у вас идея, где искать правильные уничтожения этих экземпляров?

Большое спасибо!

EDIT:

Я только что заметил, что класс KryptonButtonEx не из Криптона, а из моего приложения. Но я не думаю, что это что-то меняет в вопросе, поскольку единственное, что он делает, это переопределяет функцию GetPreferredSize:

/// <summary>
/// An extended/fixed KryptonButton which handles resizing correctly.
/// </summary>
public class KryptonButtonEx : ComponentFactory.Krypton.Toolkit.KryptonButton
{
    /// <summary>
    /// Gets the size of the preferred.
    /// </summary>
    /// <param name="proposedSize">Size of the proposed.</param>
    /// <returns></returns>
    public override Size GetPreferredSize(Size proposedSize)
    {
        // Do we have a manager to ask for a preferred size?
        if (ViewManager != null)
        {
            // Ask the view to peform a layout
            Size retSize = ViewManager.GetPreferredSize(Renderer, proposedSize);

            // Apply the maximum sizing
            if (MaximumSize.Width > 0) retSize.Width = Math.Min(MaximumSize.Width, retSize.Width);
            if (MaximumSize.Height > 0) retSize.Height = Math.Min(MaximumSize.Height, retSize.Width);

            // Apply the minimum sizing
            if (MinimumSize.Width > 0) retSize.Width = Math.Max(MinimumSize.Width, retSize.Width);
            if (MinimumSize.Height > 0) retSize.Height = Math.Max(MinimumSize.Height, retSize.Height);

            return retSize;
        }
        else
        {
            // Fall back on default control processing
            return base.GetPreferredSize(proposedSize);
        }
    }
}

1 Ответ

5 голосов
/ 27 мая 2011

Вы отправили неправильный код.Вместо кода, который создает кнопку, вы должны быть очень заинтересованы в коде, который удаляет ее.Найдите Controls.Remove и Controls.Clear и убедитесь, что каждый удаляемый элемент управления удаляется.Другая диагностика - TaskMgr.exe, вкладка Процессы.Просмотр + Выбор столбцов и отметьте объекты USER.Наблюдение того, что число постоянно растет, является жесткой подсказкой о том, что код не располагает элементами управления там, где должен.Это единственный известный мне случай не вызова Dispose (), вызывающий постоянную утечку.

Вместо Controls.Clear () используйте код, подобный следующему:

 while (panel.Controls.Count > 0) panel.Controls[0].Dispose();

Утилизация элемента управления такжеавтоматически удаляет его из коллекции родительского элемента управления.

...