Я хочу вернуть мою память! Как я могу по-настоящему распоряжаться контролем? - PullRequest
7 голосов
/ 12 января 2010

У меня есть приложение, которое я создаю, которое создает большое количество элементов управления Windows (кнопок и меток и т. Д.). Все они создаются динамически с помощью функций. У меня проблема в том, что когда я удаляю элементы управления и удаляю их, они не удаляются из памяти.

void loadALoadOfStuff()
{
    while(tabControlToClear.Controls.Count > 0)
        tabControlToClear.Controls[0].Dispose();
    //I even put in:
    GC.Collect();
    GC.WaitForPendingFinalizers();
    foreach(String pagename in globalList)
        tabControlToClear.Controls.Add(MakeATab(pagename));
}

TabPage MakeATab(string tabText)
{
    TabPage newT = new MakeATab();
    newT.Text = tabText;
    //Fill page with controls with methods like this
    return newT;
}

Теперь по какой-то причине, это просто не возвращает мне память, поэтому, когда процесс запускается 5 раз, у меня заканчивается нехватка памяти. Я новичок в объектах и ​​контролирую утилизацию, но просмотр огромной сети все еще не дал мне никаких указаний, поэтому, если у кого-то из вас есть идея, я был бы рад ее услышать.

ОБНОВЛЕНИЕ: Я наблюдал за созданием и уничтожением пользовательских объектов (TaskManager) и заметил, что я создаю вкладку, добавляю обработчик кликов, добавляю панель, добавляю 2 кнопки с обработчиками кликов, всплывающими подсказками и фоновыми изображениями (я думаю, вот где проблема). Приложение говорит, что оно создает 8 новых элементов, но когда я запускаю утилизацию, я удаляю только 4 из памяти. Я пытался удалить обработчики событий, но, похоже, это не имеет значения.

РЕШЕНО !!! Когда я добавлял новые элементы на панель, я передавал им всплывающую подсказку (глупо, но я учусь). Для тех, у кого такая же проблема, (благодаря комментариям и указаниям нижеприведенных людей. Я обнаружил, что для того, чтобы сделать элемент управления действительно доступным (как я понимаю, я так неправильно его назвал):

1: ЕСЛИ У ВАС ЕСТЬ ИНСТРУМЕНТАЛЬНЫЙ СОВЕТ, УБЕДИТЕСЬ, ЧТО ЭТО ДОСТУПНО! НЕ ДЕЛАЙТЕ ТО, ЧТО Я СДЕЛАЛ! Например:

Это НЕПРАВИЛЬНО!

TabPage MakeATab(string tabText)
{
    TabPage newT = new MakeATab();
    ToolTip myTip = new ToolTip();
    newT.Text = tabText;
    //Fill page with controls with methods like this
    myTip.SetToolTip(newT, "Something to say");
    return newT;
}

Если вы сделаете это, вы потеряете указатель на всплывающую подсказку, и поскольку всплывающая подсказка не является дочерней по отношению к объекту, к которому она подключена (скорее, всплывающая подсказка делает сильную ссылку на элемент управления), то даже если вы уничтожите элемент управления, всплывающая подсказка, к которой вы не можете получить доступ, сохраняет объект живым.

2: Прежде всего, вызовите toolTip.RemoveAll (). Это удаляет все его связи с элементами управления. Обратите внимание, что если вы использовали этот совет для других элементов управления, они просто потеряли свою подсказку.

3: Удалить все внутренние элементы управления из базового элемента управления. ControlCollection (если они используют неуправляемую память, я думаю. Я делаю это, потому что это заставляет мое приложение работать так ...)

4: удалить любые пользовательские обработчики событий.

5: наконец, избавьтесь от объекта. Я сделал функцию быстрого повторения, которая делает это довольно хорошо.

    private void RecursiveDispose(Control toDispose)
    {
        while (toDispose.Controls.Count > 0)
            RecursiveDispose(toDispose.Controls[0]);

        if (toDispose.BackgroundImage != null)
            BackgroundImage = null;

        if (toDispose.GetType() == typeof(Button))
            toDispose.Click -= [Your Event];
        else if (toDispose.GetType() == typeof(TabPage))
            toDispose.DoubleClick -= [Your Event];
        else if (toDispose.GetType() == typeof(Label))
            toDispose.MouseMove -= [Your Event];

        toDispose.Dispose();
    }

Это очень грубо, и, вероятно, есть гораздо лучший способ сделать это, но если кто-то не может придумать это, это придется делать. Спасибо за вашу помощь всем. Возможно, вы просто сохранили весь мой проект.

Ответы [ 4 ]

6 голосов
/ 12 января 2010

Вам также необходимо очистить ссылку.

while(tabControlToClear.Controls.Count > 0)
{ 
    var tabPage = tabControlToClear.Controls[0];
    tabControlToClear.Controls.RemoveAt(0);
    tabPage.Dispose(); 

    // Clear out events.

    foreach (EventHandler subscriber in tabPage.Click.GetInvocationList())
    {
        tabPage.Click -= subscriber;
    }
}
4 голосов
/ 12 января 2010

В этом блоке кода вы вызываете Dispose, но не удаляете ссылку:

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

Вам нужно удалить все ссылки на элемент управления (в коллекции Controls плюс все зарегистрированные обработчики событий плюс любые другие ссылки, которые у вас могут быть), чтобы элемент управления имел право на сборку мусора.

0 голосов
/ 12 января 2010

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

Однако, когда я получаю проблему такого типа, я использую профилировщик памяти , чтобы помочь отследить ссылки на объекты, когда я в последний раз смотрю на профилировщики памяти, ANTS Memory Profiler (из RedGate ) был одним из лучших. (У них 14-дневный хвост, которого достаточно, чтобы исследовать одну проблему, подобную этой.)

Это одна из причин, по которой используется шаблон Weak Event, однако это будет совершенно новый вопрос .

(время жизни объектов пользовательского интерфейса, когда вы динамически модифицируете пользовательский интерфейс, является минным полем, хорошо сделанным для менеджера задач, чтобы проверить, что ваш код работает должным образом)

0 голосов
/ 12 января 2010
void loadALoadOfStuff()
{
    while(tabControlToClear.Controls.Count > 0)
        tabControlToClear.Controls[0].Dispose();
    //I even put in:
    GC.Collect();
    GC.WaitForPendingFinalizers();
    foreach(String pagename in globalList)
        tabControlToClear.Controls.Add(MakeATab(pagename));
}

Мне кажется, что вы перераспределяете все экземпляры вкладок в конце вашего тестового метода, поэтому, очевидно, нет смысла сначала их удалять. Пропустите последние две строки и посмотрите, поможет ли это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...